summaryrefslogtreecommitdiffstats
path: root/kradio3/plugins
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-22 18:23:26 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-22 18:23:26 +0000
commitae364d9bed0589bf1a22cd5f530c563462379e3e (patch)
treee32727e2664e7ce68d0d30270afa040320ae35a1 /kradio3/plugins
downloadtderadio-ae364d9bed0589bf1a22cd5f530c563462379e3e.tar.gz
tderadio-ae364d9bed0589bf1a22cd5f530c563462379e3e.zip
Added old KDE3 version of kradio
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kradio@1094417 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kradio3/plugins')
-rw-r--r--kradio3/plugins/Makefile.am4
-rw-r--r--kradio3/plugins/alsa-sound/Makefile.am20
-rw-r--r--kradio3/plugins/alsa-sound/alsa-config-mixer-setting.cpp67
-rw-r--r--kradio3/plugins/alsa-sound/alsa-config-mixer-setting.h45
-rw-r--r--kradio3/plugins/alsa-sound/alsa-mixer-element-ui.ui270
-rw-r--r--kradio3/plugins/alsa-sound/alsa-mixer-element.cpp139
-rw-r--r--kradio3/plugins/alsa-sound/alsa-mixer-element.h62
-rw-r--r--kradio3/plugins/alsa-sound/alsa-sound-configuration-ui.ui323
-rw-r--r--kradio3/plugins/alsa-sound/alsa-sound-configuration.cpp353
-rw-r--r--kradio3/plugins/alsa-sound/alsa-sound-configuration.h83
-rw-r--r--kradio3/plugins/alsa-sound/alsa-sound.cpp1562
-rw-r--r--kradio3/plugins/alsa-sound/alsa-sound.h296
-rw-r--r--kradio3/plugins/alsa-sound/icons/Makefile.am2
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa.pngbin0 -> 391 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa2.pngbin0 -> 602 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa.pngbin0 -> 463 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa2.pngbin0 -> 917 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa.pngbin0 -> 606 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa2.pngbin0 -> 1362 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa.pngbin0 -> 904 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa2.pngbin0 -> 1979 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa.pngbin0 -> 1279 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa2.pngbin0 -> 2631 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/kradio_alsa.pngbin0 -> 3321 bytes
-rw-r--r--kradio3/plugins/alsa-sound/icons/kradio_alsa2.pngbin0 -> 2388 bytes
-rw-r--r--kradio3/plugins/alsa-sound/po/Makefile.am3
-rw-r--r--kradio3/plugins/alsa-sound/po/de.po289
-rw-r--r--kradio3/plugins/alsa-sound/po/ru.po288
-rw-r--r--kradio3/plugins/gui-docking-menu/Makefile.am18
-rw-r--r--kradio3/plugins/gui-docking-menu/docking-configuration.cpp114
-rw-r--r--kradio3/plugins/gui-docking-menu/docking-configuration.h54
-rw-r--r--kradio3/plugins/gui-docking-menu/docking.cpp674
-rw-r--r--kradio3/plugins/gui-docking-menu/docking.h189
-rw-r--r--kradio3/plugins/gui-docking-menu/po/Makefile.am2
-rw-r--r--kradio3/plugins/gui-docking-menu/po/de.po117
-rw-r--r--kradio3/plugins/gui-docking-menu/po/ru.po117
-rw-r--r--kradio3/plugins/gui-error-log/Makefile.am17
-rw-r--r--kradio3/plugins/gui-error-log/errorlog.cpp263
-rw-r--r--kradio3/plugins/gui-error-log/errorlog.h89
-rw-r--r--kradio3/plugins/gui-error-log/po/Makefile.am2
-rw-r--r--kradio3/plugins/gui-error-log/po/de.po69
-rw-r--r--kradio3/plugins/gui-error-log/po/ru.po71
-rw-r--r--kradio3/plugins/gui-quickbar/Makefile.am18
-rw-r--r--kradio3/plugins/gui-quickbar/buttonflowlayout.cpp232
-rw-r--r--kradio3/plugins/gui-quickbar/buttonflowlayout.h60
-rw-r--r--kradio3/plugins/gui-quickbar/po/Makefile.am2
-rw-r--r--kradio3/plugins/gui-quickbar/po/de.po53
-rw-r--r--kradio3/plugins/gui-quickbar/po/ru.po55
-rw-r--r--kradio3/plugins/gui-quickbar/quickbar-configuration.cpp35
-rw-r--r--kradio3/plugins/gui-quickbar/quickbar-configuration.h36
-rw-r--r--kradio3/plugins/gui-quickbar/quickbar.cpp424
-rw-r--r--kradio3/plugins/gui-quickbar/quickbar.h138
-rw-r--r--kradio3/plugins/gui-standard-display/Makefile.am22
-rw-r--r--kradio3/plugins/gui-standard-display/displaycfg.cpp145
-rw-r--r--kradio3/plugins/gui-standard-display/displaycfg.h72
-rw-r--r--kradio3/plugins/gui-standard-display/displaycfg_interfaces.cpp69
-rw-r--r--kradio3/plugins/gui-standard-display/displaycfg_interfaces.h82
-rw-r--r--kradio3/plugins/gui-standard-display/po/Makefile.am2
-rw-r--r--kradio3/plugins/gui-standard-display/po/de.po212
-rw-r--r--kradio3/plugins/gui-standard-display/po/ru.po213
-rw-r--r--kradio3/plugins/gui-standard-display/radioview-configuration.cpp116
-rw-r--r--kradio3/plugins/gui-standard-display/radioview-configuration.h61
-rw-r--r--kradio3/plugins/gui-standard-display/radioview.cpp807
-rw-r--r--kradio3/plugins/gui-standard-display/radioview.h207
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_element.cpp34
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_element.h66
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_frequencyradio.cpp443
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_frequencyradio.h108
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_frequencyseeker.cpp250
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_frequencyseeker.h78
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_seekinterface.ui167
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_seekinterface.ui.h21
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_volume.cpp141
-rw-r--r--kradio3/plugins/gui-standard-display/radioview_volume.h75
-rw-r--r--kradio3/plugins/lirc/Makefile.am28
-rw-r--r--kradio3/plugins/lirc/default-dot-lircrc6
-rw-r--r--kradio3/plugins/lirc/lirc-configuration-ui.ui110
-rw-r--r--kradio3/plugins/lirc/lirc-configuration.cpp193
-rw-r--r--kradio3/plugins/lirc/lirc-configuration.h60
-rw-r--r--kradio3/plugins/lirc/lircsupport.cpp553
-rw-r--r--kradio3/plugins/lirc/lircsupport.h159
-rw-r--r--kradio3/plugins/lirc/listviewitem_lirc.cpp51
-rw-r--r--kradio3/plugins/lirc/listviewitem_lirc.h51
-rw-r--r--kradio3/plugins/lirc/po/Makefile.am2
-rw-r--r--kradio3/plugins/lirc/po/de.po213
-rw-r--r--kradio3/plugins/lirc/po/ru.po209
-rw-r--r--kradio3/plugins/oss-sound/Makefile.am18
-rw-r--r--kradio3/plugins/oss-sound/icons/Makefile.am2
-rw-r--r--kradio3/plugins/oss-sound/icons/hi16-action-kradio_oss.pngbin0 -> 1042 bytes
-rw-r--r--kradio3/plugins/oss-sound/icons/hi32-action-kradio_oss.pngbin0 -> 2206 bytes
-rw-r--r--kradio3/plugins/oss-sound/icons/hi48-action-kradio_oss.pngbin0 -> 3702 bytes
-rw-r--r--kradio3/plugins/oss-sound/oss-sound-configuration-ui.ui132
-rw-r--r--kradio3/plugins/oss-sound/oss-sound-configuration.cpp86
-rw-r--r--kradio3/plugins/oss-sound/oss-sound-configuration.h51
-rw-r--r--kradio3/plugins/oss-sound/oss-sound.cpp991
-rw-r--r--kradio3/plugins/oss-sound/oss-sound.h224
-rw-r--r--kradio3/plugins/oss-sound/po/Makefile.am2
-rw-r--r--kradio3/plugins/oss-sound/po/de.po200
-rw-r--r--kradio3/plugins/oss-sound/po/ru.po193
-rw-r--r--kradio3/plugins/radio/Makefile.am18
-rw-r--r--kradio3/plugins/radio/po/Makefile.am2
-rw-r--r--kradio3/plugins/radio/po/de.po185
-rw-r--r--kradio3/plugins/radio/po/ru.po185
-rw-r--r--kradio3/plugins/radio/radio-configuration-ui.ui774
-rw-r--r--kradio3/plugins/radio/radio-configuration.cpp592
-rw-r--r--kradio3/plugins/radio/radio-configuration.h106
-rw-r--r--kradio3/plugins/radio/radio.cpp497
-rw-r--r--kradio3/plugins/radio/radio.h167
-rw-r--r--kradio3/plugins/recording/Makefile.am22
-rw-r--r--kradio3/plugins/recording/encoder.cpp172
-rw-r--r--kradio3/plugins/recording/encoder.h101
-rw-r--r--kradio3/plugins/recording/encoder_mp3.cpp214
-rw-r--r--kradio3/plugins/recording/encoder_mp3.h56
-rw-r--r--kradio3/plugins/recording/encoder_ogg.cpp250
-rw-r--r--kradio3/plugins/recording/encoder_ogg.h55
-rw-r--r--kradio3/plugins/recording/encoder_pcm.cpp78
-rw-r--r--kradio3/plugins/recording/encoder_pcm.h46
-rw-r--r--kradio3/plugins/recording/icons/Makefile.am2
-rw-r--r--kradio3/plugins/recording/icons/hi16-action-kradio_record.pngbin0 -> 480 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi16-app-kradio_plus_rec.pngbin0 -> 931 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi22-action-kradio_record.pngbin0 -> 714 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi22-app-kradio_plus_rec.pngbin0 -> 1486 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi256-action-kradio_record.pngbin0 -> 8662 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi32-action-kradio_record.pngbin0 -> 1052 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi32-app-kradio_plus_rec.pngbin0 -> 2491 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi48-action-kradio_record.pngbin0 -> 1719 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi48-app-kradio_plus_rec.pngbin0 -> 4633 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi64-action-kradio_record.pngbin0 -> 2281 bytes
-rw-r--r--kradio3/plugins/recording/icons/hi64-app-kradio_plus_rec.pngbin0 -> 6695 bytes
-rw-r--r--kradio3/plugins/recording/po/Makefile.am2
-rw-r--r--kradio3/plugins/recording/po/de.po435
-rw-r--r--kradio3/plugins/recording/po/ru.po432
-rw-r--r--kradio3/plugins/recording/reccfg_interfaces.cpp151
-rw-r--r--kradio3/plugins/recording/reccfg_interfaces.h102
-rw-r--r--kradio3/plugins/recording/recording-config.cpp215
-rw-r--r--kradio3/plugins/recording/recording-config.h73
-rw-r--r--kradio3/plugins/recording/recording-configuration-ui.ui731
-rw-r--r--kradio3/plugins/recording/recording-configuration.cpp414
-rw-r--r--kradio3/plugins/recording/recording-configuration.h126
-rw-r--r--kradio3/plugins/recording/recording-datamonitor.cpp278
-rw-r--r--kradio3/plugins/recording/recording-datamonitor.h66
-rw-r--r--kradio3/plugins/recording/recording-monitor.cpp402
-rw-r--r--kradio3/plugins/recording/recording-monitor.h124
-rw-r--r--kradio3/plugins/recording/recording.cpp736
-rw-r--r--kradio3/plugins/recording/recording.h148
-rw-r--r--kradio3/plugins/recording/soundstreamevent.h87
-rw-r--r--kradio3/plugins/soundserver/Makefile.am18
-rw-r--r--kradio3/plugins/soundserver/po/Makefile.am2
-rw-r--r--kradio3/plugins/soundserver/po/de.po29
-rw-r--r--kradio3/plugins/soundserver/po/ru.po29
-rw-r--r--kradio3/plugins/soundserver/soundserver.cpp74
-rw-r--r--kradio3/plugins/soundserver/soundserver.h54
-rw-r--r--kradio3/plugins/streaming/Makefile.am18
-rw-r--r--kradio3/plugins/streaming/icons/Makefile.am2
-rw-r--r--kradio3/plugins/streaming/icons/hi16-action-kradio_streaming.pngbin0 -> 667 bytes
-rw-r--r--kradio3/plugins/streaming/icons/hi22-action-kradio_streaming.pngbin0 -> 952 bytes
-rw-r--r--kradio3/plugins/streaming/icons/hi32-action-kradio_streaming.pngbin0 -> 1413 bytes
-rw-r--r--kradio3/plugins/streaming/icons/hi48-action-kradio_streaming.pngbin0 -> 2157 bytes
-rw-r--r--kradio3/plugins/streaming/icons/hi64-action-kradio_streaming.pngbin0 -> 2890 bytes
-rw-r--r--kradio3/plugins/streaming/po/Makefile.am2
-rw-r--r--kradio3/plugins/streaming/po/de.po226
-rw-r--r--kradio3/plugins/streaming/po/ru.po228
-rw-r--r--kradio3/plugins/streaming/streaming-configuration-ui.ui777
-rw-r--r--kradio3/plugins/streaming/streaming-configuration.cpp567
-rw-r--r--kradio3/plugins/streaming/streaming-configuration.h97
-rw-r--r--kradio3/plugins/streaming/streaming-job.cpp279
-rw-r--r--kradio3/plugins/streaming/streaming-job.h100
-rw-r--r--kradio3/plugins/streaming/streaming.cpp526
-rw-r--r--kradio3/plugins/streaming/streaming.h145
-rw-r--r--kradio3/plugins/timecontrol/Makefile.am17
-rw-r--r--kradio3/plugins/timecontrol/icons/Makefile.am2
-rw-r--r--kradio3/plugins/timecontrol/icons/hi16-action-kradio_kalarm.pngbin0 -> 496 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi16-action-kradio_zzz.pngbin0 -> 347 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi22-action-kradio_kalarm.pngbin0 -> 830 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi22-action-kradio_zzz.pngbin0 -> 865 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi32-action-kradio_kalarm.pngbin0 -> 1515 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi32-action-kradio_zzz.pngbin0 -> 1476 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi330-action-kradio_zzz.pngbin0 -> 17712 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi48-action-kradio_kalarm.pngbin0 -> 1989 bytes
-rw-r--r--kradio3/plugins/timecontrol/icons/hi48-action-kradio_zzz.pngbin0 -> 2347 bytes
-rw-r--r--kradio3/plugins/timecontrol/po/Makefile.am2
-rw-r--r--kradio3/plugins/timecontrol/po/de.po129
-rw-r--r--kradio3/plugins/timecontrol/po/ru.po129
-rw-r--r--kradio3/plugins/timecontrol/timecontrol-configuration-ui.ui452
-rw-r--r--kradio3/plugins/timecontrol/timecontrol-configuration.cpp425
-rw-r--r--kradio3/plugins/timecontrol/timecontrol-configuration.h90
-rw-r--r--kradio3/plugins/timecontrol/timecontrol.cpp301
-rw-r--r--kradio3/plugins/timecontrol/timecontrol.h95
-rw-r--r--kradio3/plugins/timeshifter/Makefile.am18
-rw-r--r--kradio3/plugins/timeshifter/icons/Makefile.am2
-rw-r--r--kradio3/plugins/timeshifter/icons/hi16-action-kradio_pause.pngbin0 -> 850 bytes
-rw-r--r--kradio3/plugins/timeshifter/icons/hi16-app-kradio_plus_pause.pngbin0 -> 991 bytes
-rw-r--r--kradio3/plugins/timeshifter/icons/hi22-action-kradio_pause.pngbin0 -> 1190 bytes
-rw-r--r--kradio3/plugins/timeshifter/icons/hi22-app-kradio_plus_pause.pngbin0 -> 1584 bytes
-rw-r--r--kradio3/plugins/timeshifter/icons/hi32-action-kradio_pause.pngbin0 -> 1504 bytes
-rw-r--r--kradio3/plugins/timeshifter/icons/hi32-app-kradio_plus_pause.pngbin0 -> 2748 bytes
-rw-r--r--kradio3/plugins/timeshifter/icons/hi48-app-kradio_plus_pause.pngbin0 -> 4947 bytes
-rw-r--r--kradio3/plugins/timeshifter/icons/hi64-app-kradio_plus_pause.pngbin0 -> 6935 bytes
-rw-r--r--kradio3/plugins/timeshifter/po/Makefile.am3
-rw-r--r--kradio3/plugins/timeshifter/po/de.po91
-rw-r--r--kradio3/plugins/timeshifter/po/ru.po91
-rw-r--r--kradio3/plugins/timeshifter/timeshifter-configuration-ui.ui225
-rw-r--r--kradio3/plugins/timeshifter/timeshifter-configuration.cpp203
-rw-r--r--kradio3/plugins/timeshifter/timeshifter-configuration.h83
-rw-r--r--kradio3/plugins/timeshifter/timeshifter.cpp455
-rw-r--r--kradio3/plugins/timeshifter/timeshifter.h120
-rw-r--r--kradio3/plugins/v4lradio/Makefile.am18
-rw-r--r--kradio3/plugins/v4lradio/linux/videodev.h432
-rw-r--r--kradio3/plugins/v4lradio/linux/videodev2.h940
-rw-r--r--kradio3/plugins/v4lradio/po/Makefile.am3
-rw-r--r--kradio3/plugins/v4lradio/po/de.po362
-rw-r--r--kradio3/plugins/v4lradio/po/ru.po362
-rw-r--r--kradio3/plugins/v4lradio/v4lcfg_interfaces.cpp193
-rw-r--r--kradio3/plugins/v4lradio/v4lcfg_interfaces.h151
-rw-r--r--kradio3/plugins/v4lradio/v4lradio-configuration-ui.ui966
-rw-r--r--kradio3/plugins/v4lradio/v4lradio-configuration.cpp648
-rw-r--r--kradio3/plugins/v4lradio/v4lradio-configuration.h147
-rw-r--r--kradio3/plugins/v4lradio/v4lradio.cpp1621
-rw-r--r--kradio3/plugins/v4lradio/v4lradio.h265
219 files changed, 33838 insertions, 0 deletions
diff --git a/kradio3/plugins/Makefile.am b/kradio3/plugins/Makefile.am
new file mode 100644
index 0000000..3e9e46f
--- /dev/null
+++ b/kradio3/plugins/Makefile.am
@@ -0,0 +1,4 @@
+INCLUDES =
+METASOURCES = AUTO
+SUBDIRS = gui-docking-menu gui-error-log gui-quickbar gui-standard-display $(PLUGIN_LIRC) \
+ radio timecontrol v4lradio $(PLUGIN_OSS) soundserver recording timeshifter $(PLUGIN_ALSA) streaming
diff --git a/kradio3/plugins/alsa-sound/Makefile.am b/kradio3/plugins/alsa-sound/Makefile.am
new file mode 100644
index 0000000..a00e32c
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/Makefile.am
@@ -0,0 +1,20 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libalsa-sound.la
+libalsa_sound_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+noinst_HEADERS = alsa-sound.h alsa-sound-configuration.h alsa-mixer-element.h \
+ alsa-config-mixer-setting.h
+libalsa_sound_la_SOURCES = alsa-sound.cpp alsa-sound-configuration-ui.ui \
+ alsa-sound-configuration.cpp alsa-mixer-element-ui.ui alsa-mixer-element.cpp \
+ alsa-config-mixer-setting.cpp
+libalsa_sound_la_LIBADD = $(LIB_ALSA)
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-alsa-sound.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-alsa-sound.pot
diff --git a/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.cpp b/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.cpp
new file mode 100644
index 0000000..873b29e
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+ alsa-config-mixer-setting.cpp - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 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 "alsa-config-mixer-setting.h"
+
+#include <kconfig.h>
+
+AlsaConfigMixerSetting::AlsaConfigMixerSetting()
+ : m_card(-1),
+ m_name(QString::null),
+ m_use(false),
+ m_active(false),
+ m_volume(-1)
+{
+}
+
+AlsaConfigMixerSetting::AlsaConfigMixerSetting(KConfig *c, const QString &prefix)
+{
+ m_card = c->readNumEntry (prefix+"card", -1);
+ m_name = c->readEntry (prefix+"name", QString::null);
+ m_use = c->readBoolEntry (prefix+"use", false);
+ m_active = c->readBoolEntry (prefix+"active", false);
+ m_volume = c->readDoubleNumEntry(prefix+"volume", 0);
+}
+
+AlsaConfigMixerSetting::AlsaConfigMixerSetting(int card, const QString &name, bool use, bool active, float volume)
+ : m_card(card),
+ m_name(name),
+ m_use(use),
+ m_active(active),
+ m_volume(volume)
+{
+}
+
+AlsaConfigMixerSetting::~AlsaConfigMixerSetting()
+{
+}
+
+QString AlsaConfigMixerSetting::getIDString(int card, const QString &name)
+{
+ return QString::number(card) + "-" + name;
+}
+
+void AlsaConfigMixerSetting::saveState(KConfig *c, const QString &prefix) const
+{
+ c->writeEntry(prefix+"card", m_card);
+ c->writeEntry(prefix+"name", m_name);
+ c->writeEntry(prefix+"use", m_use);
+ c->writeEntry(prefix+"active", m_active);
+ c->writeEntry(prefix+"volume", m_volume);
+}
+
+
diff --git a/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.h b/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.h
new file mode 100644
index 0000000..a9f5d88
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ alsa-config-mixer-setting.h - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KRADIO_ALSA_CONFIG_MIXER_SETTING_H
+#define __KRADIO_ALSA_CONFIG_MIXER_SETTING_H
+
+#include <qstring.h>
+
+class KConfig;
+
+class AlsaConfigMixerSetting
+{
+public:
+ AlsaConfigMixerSetting();
+ AlsaConfigMixerSetting(KConfig *c, const QString &prefix);
+ AlsaConfigMixerSetting(int card, const QString &name, bool use, bool active, float volume);
+ ~AlsaConfigMixerSetting();
+
+ QString getIDString() const { return getIDString(m_card, m_name); }
+ static QString getIDString(int card, const QString &m_name);
+
+ void saveState(KConfig *c, const QString &prefix) const;
+
+ int m_card;
+ QString m_name;
+ bool m_use;
+ bool m_active;
+ float m_volume;
+};
+
+#endif
diff --git a/kradio3/plugins/alsa-sound/alsa-mixer-element-ui.ui b/kradio3/plugins/alsa-sound/alsa-mixer-element-ui.ui
new file mode 100644
index 0000000..e2c170d
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-mixer-element-ui.ui
@@ -0,0 +1,270 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AlsaMixerElementUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>AlsaMixerElementUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>124</width>
+ <height>153</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form1</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer>
+ <property name="name">
+ <cstring>spacer23</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>1</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>m_sliderVolume</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer23_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>1</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>11</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>m_spinboxVolume</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>11</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkboxActive</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>O&amp;n</string>
+ </property>
+ <property name="accel">
+ <string>Alt+N</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkboxOverride</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use</string>
+ </property>
+ <property name="accel">
+ <string>Alt+U</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_labelMixerElementName</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>MixerName</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="2"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/alsa-sound/alsa-mixer-element.cpp b/kradio3/plugins/alsa-sound/alsa-mixer-element.cpp
new file mode 100644
index 0000000..1fbc75a
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-mixer-element.cpp
@@ -0,0 +1,139 @@
+/***************************************************************************
+ alsa-mixer-element.cpp - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 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 "alsa-mixer-element.h"
+
+#include <knuminput.h>
+#include <qslider.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+
+#include <math.h>
+
+QAlsaMixerElement::QAlsaMixerElement(QWidget *parent, const QString &label, bool has_switch, bool has_volume)
+ : AlsaMixerElementUI(parent),
+ m_HasVolume(has_volume),
+ m_HasSwitch(has_switch),
+ m_dirty(false),
+ m_ignore_updates(false)
+{
+ setLabel(label);
+ setVolume(0);
+
+ QObject::connect(m_spinboxVolume, SIGNAL(valueChanged(int)),
+ this, SLOT (slotSpinboxValueChanged(int)));
+ QObject::connect(m_sliderVolume, SIGNAL(valueChanged(int)),
+ this, SLOT (slotSliderValueChanged(int)));
+
+ if (m_HasVolume) {
+ QObject::connect(m_checkboxOverride, SIGNAL(toggled(bool)),
+ m_spinboxVolume, SLOT (setEnabled(bool)));
+ QObject::connect(m_checkboxOverride, SIGNAL(toggled(bool)),
+ m_sliderVolume, SLOT (setEnabled(bool)));
+ } else {
+ m_spinboxVolume->hide();
+ m_sliderVolume->hide();
+ }
+ if (m_HasSwitch) {
+ QObject::connect(m_checkboxOverride, SIGNAL(toggled(bool)),
+ m_checkboxActive, SLOT (setEnabled(bool)));
+ } else {
+ //m_checkboxActive->hide();
+ m_checkboxActive->setEnabled(false);
+ m_checkboxActive->setChecked(true);
+ }
+
+ connect(m_checkboxOverride, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+ connect(m_checkboxActive, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+ connect(m_spinboxVolume, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+ connect(m_sliderVolume, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+}
+
+
+QAlsaMixerElement::~QAlsaMixerElement()
+{
+}
+
+float QAlsaMixerElement::getVolume() const
+{
+ return ((float)m_spinboxVolume->value())/100.0;
+}
+
+bool QAlsaMixerElement::getActive() const
+{
+ return m_checkboxActive->isChecked();
+}
+
+bool QAlsaMixerElement::getOverride() const
+{
+ return m_checkboxOverride->isChecked();
+}
+
+void QAlsaMixerElement::setLabel(const QString &label)
+{
+ m_labelMixerElementName->setText(label);
+}
+
+void QAlsaMixerElement::setOverride(bool ov)
+{
+ m_ignore_updates = true;
+ m_checkboxOverride->setChecked(ov);
+ m_ignore_updates = false;
+}
+
+void QAlsaMixerElement::setActive(bool active)
+{
+ m_ignore_updates = true;
+ m_checkboxActive->setChecked(active);
+ m_ignore_updates = false;
+}
+
+void QAlsaMixerElement::setVolume(float vol)
+{
+ m_ignore_updates = true;
+ int v = (int)rint(vol*100 + 0.5);
+ m_sliderVolume->setValue(100 - v);
+ m_spinboxVolume->setValue(v);
+ m_ignore_updates = false;
+}
+
+void QAlsaMixerElement::slotSpinboxValueChanged(int v)
+{
+ m_sliderVolume->setValue(100-v);
+}
+
+void QAlsaMixerElement::slotSliderValueChanged(int v)
+{
+ m_spinboxVolume->setValue(100-v);
+}
+
+
+void QAlsaMixerElement::slotSetDirty()
+{
+ if (!m_dirty && !m_ignore_updates) {
+ m_dirty = true;
+ emit sigDirty();
+ }
+}
+
+
+void QAlsaMixerElement::slotResetDirty()
+{
+ m_dirty = false;
+}
+
+#include "alsa-mixer-element.moc"
diff --git a/kradio3/plugins/alsa-sound/alsa-mixer-element.h b/kradio3/plugins/alsa-sound/alsa-mixer-element.h
new file mode 100644
index 0000000..149e0b9
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-mixer-element.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ alsa-mixer-element.h - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KRADIO_ALSA_MIXER_ELEMENT_H
+#define __KRADIO_ALSA_MIXER_ELEMENT_H
+
+#include "alsa-mixer-element-ui.h"
+
+class QAlsaMixerElement : public AlsaMixerElementUI
+{
+Q_OBJECT
+public:
+ QAlsaMixerElement(QWidget *parent, const QString &label, bool has_switch, bool has_volume);
+ ~QAlsaMixerElement();
+
+
+ float getVolume() const;
+ bool getActive() const;
+ bool getOverride() const;
+
+ bool isDirty() const { return m_dirty; }
+
+public slots:
+
+ void setLabel(const QString &label);
+ void setOverride(bool ov);
+ void setActive(bool active);
+ void setVolume(float vol);
+ void slotResetDirty();
+ void slotSetDirty();
+
+protected slots:
+ void slotSpinboxValueChanged(int v);
+ void slotSliderValueChanged(int v);
+
+signals:
+
+ void sigDirty();
+
+protected:
+
+ bool m_HasVolume;
+ bool m_HasSwitch;
+ bool m_dirty;
+ bool m_ignore_updates;
+};
+
+#endif
diff --git a/kradio3/plugins/alsa-sound/alsa-sound-configuration-ui.ui b/kradio3/plugins/alsa-sound/alsa-sound-configuration-ui.ui
new file mode 100644
index 0000000..d1d2105
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-sound-configuration-ui.ui
@@ -0,0 +1,323 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AlsaSoundConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>AlsaSoundConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>475</width>
+ <height>260</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>AlsaSoundConfigurationUI</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>kTabWidget8</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Devices</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer114</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout58</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Capture Card</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <property name="name">
+ <cstring>m_comboCaptureCard</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Hardware Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>m_comboCaptureDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="5" column="1">
+ <property name="name">
+ <cstring>editBufferSize</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> kB</string>
+ </property>
+ <property name="maxValue">
+ <number>1024</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="4" column="1">
+ <property name="name">
+ <cstring>editHWBufferSize</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> kB</string>
+ </property>
+ <property name="maxValue">
+ <number>1024</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_comboPlaybackCard</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_comboPlaybackDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Playback Device</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Capture Device</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Playback Card</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>E&amp;xtended Options</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>chkDisablePlayback</cstring>
+ </property>
+ <property name="text">
+ <string>Disable Pla&amp;yback</string>
+ </property>
+ <property name="accel">
+ <string>Alt+Y</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>chkDisableCapture</cstring>
+ </property>
+ <property name="text">
+ <string>Disa&amp;ble Capture</string>
+ </property>
+ <property name="accel">
+ <string>Alt+B</string>
+ </property>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer113</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Capture Mixer Settings</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_groupMixer</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/alsa-sound/alsa-sound-configuration.cpp b/kradio3/plugins/alsa-sound/alsa-sound-configuration.cpp
new file mode 100644
index 0000000..f4914f2
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-sound-configuration.cpp
@@ -0,0 +1,353 @@
+/***************************************************************************
+ alsa-sound-configuration.cpp - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 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 <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlayout.h>
+#include <qscrollview.h>
+
+#include <kurlrequester.h>
+#include <knuminput.h>
+#include <klineedit.h>
+#include <kcombobox.h>
+#include <ktabwidget.h>
+#include <klocale.h>
+
+#include "alsa-mixer-element.h"
+#include "alsa-sound-configuration.h"
+#include "alsa-sound.h"
+
+
+AlsaSoundConfiguration::AlsaSoundConfiguration (QWidget *parent, AlsaSoundDevice *dev)
+ : AlsaSoundConfigurationUI(parent),
+ m_SoundDevice (dev),
+ m_groupMixerLayout(NULL),
+ m_groupMixerScrollView(NULL),
+ m_groupMixerSubFrame(NULL),
+ m_dirty(true),
+ m_ignore_updates(false)
+{
+ QObject::connect(m_comboPlaybackCard, SIGNAL(activated(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(m_comboCaptureCard, SIGNAL(activated(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(m_comboPlaybackDevice, SIGNAL(activated(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(m_comboCaptureDevice, SIGNAL(activated(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(editHWBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(editBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(chkDisablePlayback, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+ QObject::connect(chkDisableCapture, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+
+ QObject::connect(m_comboPlaybackCard, SIGNAL(activated(const QString &)),
+ this, SLOT(slotPlaybackCardSelected(const QString &)));
+ QObject::connect(m_comboCaptureCard, SIGNAL(activated(const QString &)),
+ this, SLOT(slotCaptureCardSelected(const QString &)));
+
+ m_groupMixer->setColumnLayout(0, Qt::Horizontal );
+
+ QHBoxLayout *tmp_layout = new QHBoxLayout( m_groupMixer->layout() );
+
+ m_groupMixerScrollView = new QScrollView (m_groupMixer);
+ m_groupMixerScrollView->setFrameShape(QFrame::NoFrame);
+ m_groupMixerScrollView->setFrameShadow(QFrame::Plain);
+ m_groupMixerScrollView->enableClipper(true);
+ m_groupMixerScrollView->setResizePolicy(QScrollView::AutoOneFit);
+ //m_groupMixerScrollView->setHScrollBarMode(QScrollView::AlwaysOn);
+
+ tmp_layout->addWidget(m_groupMixerScrollView);
+
+
+ int card = -1;
+ int ret = 0;
+ int idx_playback = 0;
+ int idx_capture = 0;
+ while ((ret = snd_card_next(&card)) == 0) {
+ char *name = NULL;
+ if (card >= 0 && snd_card_get_longname(card, &name) == 0) {
+ if (name) {
+ m_name2card[name] = card;
+ m_card2name[card] = name;
+ if (listSoundDevices(NULL, NULL, NULL, NULL, card, SND_PCM_STREAM_PLAYBACK)) {
+ m_comboPlaybackCard->insertItem(name);
+ m_playbackCard2idx[card] = idx_playback++;
+ }
+ if (listSoundDevices(NULL, NULL, NULL, NULL, card, SND_PCM_STREAM_CAPTURE)) {
+ m_comboCaptureCard->insertItem(name);
+ m_captureCard2idx[card] = idx_capture++;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ slotCancel();
+}
+
+
+AlsaSoundConfiguration::~AlsaSoundConfiguration ()
+{
+}
+
+
+void AlsaSoundConfiguration::slotPlaybackCardSelected(const QString &cardname)
+{
+ if (!m_name2card.contains(cardname))
+ return;
+
+ listSoundDevices(m_comboPlaybackDevice, &m_playbackDeviceName2dev, &m_dev2playbackDeviceName, &m_playbackDevice2idx, m_name2card[cardname], SND_PCM_STREAM_PLAYBACK);
+}
+
+
+void AlsaSoundConfiguration::slotCaptureCardSelected(const QString &cardname)
+{
+ if (!m_name2card.contains(cardname))
+ return;
+
+ saveCaptureMixerSettings();
+
+ listSoundDevices(m_comboCaptureDevice, &m_captureDeviceName2dev, &m_dev2captureDeviceName, &m_captureDevice2idx, m_name2card[cardname], SND_PCM_STREAM_CAPTURE);
+
+ m_currentCaptureCard = m_name2card[cardname];
+
+ QStringList vol_list, sw_list, all_list;
+ QMap<QString, AlsaMixerElement> vol_ch2id, sw_ch2id;
+ AlsaSoundDevice::getCaptureMixerChannels(m_name2card[cardname], NULL, vol_list, vol_ch2id, sw_list, sw_ch2id, &all_list);
+
+ for (QMapIterator<QString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
+ delete *it;
+ }
+ m_MixerElements.clear();
+
+ if (m_groupMixerSubFrame)
+ delete m_groupMixerSubFrame;
+
+ m_groupMixerSubFrame = new QFrame(m_groupMixerScrollView->viewport());
+ m_groupMixerSubFrame->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+ m_groupMixerScrollView->addChild(m_groupMixerSubFrame);
+
+ int rows = 1;
+ int cols = (all_list.count()+rows-1)/rows;
+ m_groupMixerLayout = new QGridLayout( m_groupMixerSubFrame, rows, cols, 0, 0 );
+ m_groupMixerLayout->setAlignment( Qt::AlignBottom );
+
+ int idx = 0;
+ for (QValueListConstIterator<QString> it = all_list.begin(); it != all_list.end(); ++it, ++idx) {
+ QAlsaMixerElement *e = new QAlsaMixerElement(m_groupMixerSubFrame, *it,
+ sw_list.contains(*it), vol_list.contains(*it));
+ QObject::connect(e, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+ m_groupMixerLayout->addWidget(e, idx > cols, idx % cols);
+ e->show();
+ m_MixerElements.insert(*it, e);
+ }
+ restoreCaptureMixerSettings();
+ m_groupMixerSubFrame->show();
+}
+
+void AlsaSoundConfiguration::saveCaptureMixerSettings()
+{
+ for (QMapIterator<QString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
+ const QString &name = it.key();
+ int card = m_currentCaptureCard;
+ QString id = AlsaConfigMixerSetting::getIDString(card, name);
+ QAlsaMixerElement *e = *it;
+ float vol = e->getVolume();
+ bool use = e->getOverride();
+ bool active = e->getActive();
+ e->slotResetDirty();
+ m_MixerSettings[id] = AlsaConfigMixerSetting(card,name,use,active,vol);
+ }
+}
+
+void AlsaSoundConfiguration::restoreCaptureMixerSettings()
+{
+ for (QMapIterator<QString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
+ const QString &name = it.key();
+ int card = m_currentCaptureCard;
+ QString id = AlsaConfigMixerSetting::getIDString(card, name);
+ QAlsaMixerElement *e = *it;
+
+ if (m_MixerSettings.contains(id)) {
+ const AlsaConfigMixerSetting &s = m_MixerSettings[id];
+ e->setVolume(s.m_volume);
+ e->setOverride(s.m_use);
+ e->setActive(s.m_active);
+ e->slotResetDirty();
+ } else {
+ if (name == "ADC") {
+ e->setOverride(true);
+ e->setActive(true);
+ e->setVolume(1.0);
+ }
+ else if (name == "Digital") {
+ e->setOverride(true);
+ e->setActive(true);
+ e->setVolume(1.0);
+ }
+ else if (name == "Wave") {
+ e->setOverride(true);
+ e->setActive(false);
+ e->setVolume(0);
+ }
+ else if (name == "Capture") {
+ e->setOverride(true);
+ e->setActive(true);
+ e->setVolume(0.01);
+ }
+ e->slotSetDirty();
+ }
+ }
+}
+
+int AlsaSoundConfiguration::listSoundDevices(KComboBox *combobox, QMap<QString, int> *devname2dev, QMap<int, QString> *dev2devname, QMap<int, int> *dev2idx, int card, snd_pcm_stream_t stream)
+{
+ snd_ctl_t *handle = NULL;
+ int dev = -1;
+ snd_ctl_card_info_t *info = NULL;
+ snd_pcm_info_t *pcminfo = NULL;
+
+ snd_ctl_card_info_alloca(&info);
+ snd_pcm_info_alloca (&pcminfo);
+
+ QString ctlname = "hw:"+QString::number(card);
+
+ if (combobox)
+ combobox->clear();
+ if (devname2dev)
+ devname2dev->clear();
+ if (dev2devname)
+ dev2devname->clear();
+ if (dev2idx)
+ dev2idx->clear();
+
+ int count = 0;
+
+ if (snd_ctl_open (&handle, ctlname.ascii(), 0) == 0) {
+ if (snd_ctl_card_info(handle, info) == 0) {
+
+ dev = -1;
+ while (1) {
+ if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
+ //logError("snd_ctl_pcm_next_device");
+ }
+ if (dev < 0)
+ break;
+ snd_pcm_info_set_device(pcminfo, dev);
+ snd_pcm_info_set_subdevice(pcminfo, 0);
+ snd_pcm_info_set_stream(pcminfo, stream);
+ int err = 0;
+ if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
+ if (err != -ENOENT) {
+ //logError(QString("control digital audio info (%1): %2").arg(card).arg(snd_strerror(err)));
+ }
+ continue;
+ }
+ const char *dev_name = snd_pcm_info_get_name(pcminfo);
+ QString devname = i18n("context-card-plus-device-number", "%1 device %2").arg(dev_name).arg(dev);
+ if (combobox)
+ combobox->insertItem(devname);
+ if (devname2dev)
+ (*devname2dev)[devname] = dev;
+ if (dev2devname)
+ (*dev2devname)[dev] = devname;
+ if (dev2idx)
+ (*dev2idx)[dev] = count;
+ ++count;
+ }
+ }
+ snd_ctl_close(handle);
+ }
+ return count;
+}
+
+void AlsaSoundConfiguration::slotOK()
+{
+ if (!m_dirty)
+ return;
+
+ if (m_SoundDevice) {
+ m_SoundDevice->setHWBufferSize ( editHWBufferSize ->value() * 1024);
+ m_SoundDevice->setBufferSize ( editBufferSize ->value() * 1024);
+ m_SoundDevice->enablePlayback (!chkDisablePlayback->isChecked());
+ m_SoundDevice->enableCapture (!chkDisableCapture ->isChecked());
+
+ int card = m_name2card[m_comboPlaybackCard->currentText()];
+ int device = m_playbackDeviceName2dev[m_comboPlaybackDevice->currentText()];
+ m_SoundDevice->setPlaybackDevice( card, device);
+ card = m_name2card[m_comboCaptureCard->currentText()];
+ device = m_captureDeviceName2dev[m_comboCaptureDevice->currentText()];
+ m_SoundDevice->setCaptureDevice ( card, device);
+
+ saveCaptureMixerSettings();
+ m_SoundDevice->setCaptureMixerSettings(m_MixerSettings);
+ }
+ m_dirty = false;
+}
+
+
+void AlsaSoundConfiguration::slotCancel()
+{
+ if (!m_dirty)
+ return;
+ m_ignore_updates = true;
+
+ int card = m_SoundDevice ? m_SoundDevice->getPlaybackCard() : 0;
+ int dev = m_SoundDevice ? m_SoundDevice->getPlaybackDevice() : 0;
+ m_comboPlaybackCard ->setCurrentItem(m_playbackCard2idx[card]);
+ slotPlaybackCardSelected(m_comboPlaybackCard->currentText());
+ m_comboPlaybackDevice->setCurrentItem(m_playbackDevice2idx[dev]);
+
+ card = m_SoundDevice ? m_SoundDevice->getCaptureCard() : 0;
+ dev = m_SoundDevice ? m_SoundDevice->getCaptureDevice() : 0;
+ m_comboCaptureCard ->setCurrentItem(m_captureCard2idx[card]);
+ slotCaptureCardSelected(m_comboCaptureCard->currentText());
+ m_comboCaptureDevice->setCurrentItem(m_captureDevice2idx[dev]);
+
+ //IErrorLogClient::staticLogDebug(QString("capture: card = %1(%2), dev = %3").arg(card).arg(m_captureCard2idx[card]).arg(dev));
+
+ editHWBufferSize ->setValue (m_SoundDevice ? m_SoundDevice->getHWBufferSize()/1024 : 4);
+ editBufferSize ->setValue (m_SoundDevice ? m_SoundDevice->getBufferSize()/1024 : 4);
+ chkDisablePlayback->setChecked(m_SoundDevice ? !m_SoundDevice->isPlaybackEnabled() : false);
+ chkDisableCapture ->setChecked(m_SoundDevice ? !m_SoundDevice->isCaptureEnabled() : false);
+
+ //IErrorLogClient::staticLogDebug(QString("capture: card = %1").arg(m_comboCaptureCard->currentText()));
+
+
+ if (m_SoundDevice)
+ m_MixerSettings = m_SoundDevice->getCaptureMixerSettings();
+ else
+ m_MixerSettings.clear();
+ restoreCaptureMixerSettings();
+
+ m_ignore_updates = false;
+ m_dirty = false;
+}
+
+
+void AlsaSoundConfiguration::slotUpdateConfig()
+{
+ slotSetDirty();
+ slotCancel();
+}
+
+void AlsaSoundConfiguration::slotSetDirty()
+{
+ if (!m_dirty && !m_ignore_updates) {
+ m_dirty = true;
+ //emit sigDirty();
+ }
+}
+
+#include "alsa-sound-configuration.moc"
diff --git a/kradio3/plugins/alsa-sound/alsa-sound-configuration.h b/kradio3/plugins/alsa-sound/alsa-sound-configuration.h
new file mode 100644
index 0000000..0dd361a
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-sound-configuration.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ alsa-sound-configuration.h - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_ALSA_SOUND_CONFIGURATION_H
+#define KRADIO_ALSA_SOUND_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "alsa-sound-configuration-ui.h"
+#include "alsa-sound.h"
+#include "alsa-config-mixer-setting.h"
+
+class QHBoxLayout;
+class QGridLayout;
+class QAlsaMixerElement;
+class QScrollView;
+class QFrame;
+
+class AlsaSoundConfiguration : public AlsaSoundConfigurationUI
+{
+Q_OBJECT
+public :
+ AlsaSoundConfiguration (QWidget *parent, AlsaSoundDevice *);
+ ~AlsaSoundConfiguration ();
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+
+ void slotSetDirty();
+
+ void slotUpdateConfig();
+
+ void slotPlaybackCardSelected(const QString &cardname);
+ void slotCaptureCardSelected(const QString &cardname);
+
+protected:
+ int listSoundDevices(KComboBox *combobox, QMap<QString, int> *devname2dev, QMap<int, QString> *dev2devname, QMap<int, int> *dev2idx, int card, snd_pcm_stream_t stream);
+ void saveCaptureMixerSettings();
+ void restoreCaptureMixerSettings();
+
+ AlsaSoundDevice *m_SoundDevice;
+ int m_currentCaptureCard;
+ QMap<QString, int> m_name2card,
+ m_name2capturedevice,
+ m_playbackDeviceName2dev,
+ m_captureDeviceName2dev;
+ QMap<int, QString> m_card2name,
+ m_dev2playbackDeviceName,
+ m_dev2captureDeviceName;
+ QMap<int, int> m_captureCard2idx,
+ m_captureDevice2idx,
+ m_playbackCard2idx,
+ m_playbackDevice2idx;
+ QGridLayout *m_groupMixerLayout;
+ QScrollView *m_groupMixerScrollView;
+ QFrame *m_groupMixerSubFrame;
+ QMap<QString, QAlsaMixerElement*> m_MixerElements;
+
+ QMap<QString, AlsaConfigMixerSetting> m_MixerSettings;
+
+ bool m_dirty;
+ bool m_ignore_updates;
+};
+
+#endif
diff --git a/kradio3/plugins/alsa-sound/alsa-sound.cpp b/kradio3/plugins/alsa-sound/alsa-sound.cpp
new file mode 100644
index 0000000..d67d5c8
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-sound.cpp
@@ -0,0 +1,1562 @@
+/***************************************************************************
+ alsa-sound.cpp - description
+ -------------------
+ begin : Thu May 26 2005
+ copyright : (C) 2005 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 <klocale.h>
+#include <kaboutdata.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+#include <errno.h>
+
+#include <sys/soundcard.h>
+#include <alsa/asoundlib.h>
+
+#include "alsa-sound.h"
+#include "alsa-sound-configuration.h"
+// #include "capture-thread.h"
+#include "../../src/include/aboutwidget.h"
+#include "../../src/include/utils.h"
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS(AlsaSoundDevice, "kradio-alsa-sound", i18n("Advanced Linux Sound Architecture (ALSA) Support"));
+
+/////////////////////////////////////////////////////////////////////////////
+
+struct _lrvol { unsigned char l, r; short dummy; };
+
+AlsaSoundDevice::AlsaSoundDevice(const QString &name)
+ : QObject(NULL, NULL),
+ PluginBase(name, i18n("KRadio ALSA Sound Plugin")),
+ m_hPlayback(NULL),
+ m_hCapture(NULL),
+ m_hPlaybackMixer(NULL),
+ m_hCaptureMixer(NULL),
+ m_PlaybackFormat(),
+ m_CaptureFormat(),
+ m_PlaybackCard(-1),
+ m_PlaybackDevice(-1),
+ m_CaptureCard(-1),
+ m_CaptureDevice(-1),
+ m_PlaybackLatency(50),
+ m_CaptureLatency(50),
+ m_PassivePlaybackStreams(),
+ m_PlaybackStreamID(),
+ m_CaptureStreamID(),
+ m_HWBufferSize(2048),
+ m_BufferSize(16384),
+ m_PlaybackBuffer(m_BufferSize),
+ m_CaptureBuffer(m_BufferSize),
+ m_CaptureRequestCounter(0),
+ m_CapturePos(0),
+ m_CaptureStartTime(0),
+// m_PlaybackSkipCount(0),
+ m_CaptureSkipCount(0),
+ m_EnablePlayback(true),
+ m_EnableCapture(true)//,
+// m_captureThread(NULL)
+{
+ QObject::connect(&m_PlaybackPollingTimer, SIGNAL(timeout()), this, SLOT(slotPollPlayback()));
+ QObject::connect(&m_CapturePollingTimer, SIGNAL(timeout()), this, SLOT(slotPollCapture()));
+}
+
+
+AlsaSoundDevice::~AlsaSoundDevice()
+{
+ stopCapture(m_CaptureStreamID);
+ stopPlayback(m_PlaybackStreamID);
+ closePlaybackDevice();
+ closeCaptureDevice();
+ closePlaybackMixerDevice();
+ closeCaptureMixerDevice();
+}
+
+
+bool AlsaSoundDevice::connectI(Interface *i)
+{
+ bool a = PluginBase::connectI(i);
+ bool b = ISoundStreamClient::connectI(i);
+ return a || b;
+}
+
+
+bool AlsaSoundDevice::disconnectI(Interface *i)
+{
+ bool a = PluginBase::disconnectI(i);
+ bool b = ISoundStreamClient::disconnectI(i);
+ return a || b;
+}
+
+void AlsaSoundDevice::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_sendReleasePlayback(this);
+ s->register4_sendReleaseCapture(this);
+ s->register4_sendPlaybackVolume(this);
+ s->register4_sendMute(this);
+ s->register4_sendUnmute(this);
+ s->register4_sendCaptureVolume(this);
+ s->register4_queryPlaybackVolume(this);
+ s->register4_queryCaptureVolume(this);
+ s->register4_sendStartPlayback(this);
+ s->register4_sendPausePlayback(this);
+ s->register4_sendStopPlayback(this);
+ s->register4_queryIsPlaybackRunning(this);
+ s->register4_sendStartCaptureWithFormat(this);
+ s->register4_sendStopCapture(this);
+ s->register4_queryIsCaptureRunning(this);
+ s->register4_notifySoundStreamClosed(this);
+ s->register4_notifySoundStreamRedirected(this);
+ s->register4_notifySoundStreamData(this);
+ }
+}
+
+// PluginBase
+
+void AlsaSoundDevice::saveState (KConfig *c) const
+{
+ c->setGroup(QString("alsa-sound-") + PluginBase::name());
+
+ c->writeEntry("playback-card", m_PlaybackCard);
+ c->writeEntry("playback-device", m_PlaybackDevice);
+ c->writeEntry("capture-card", m_CaptureCard);
+ c->writeEntry("capture-device", m_CaptureDevice);
+ c->writeEntry("enable-playback", m_EnablePlayback);
+ c->writeEntry("enable-capture", m_EnableCapture);
+ c->writeEntry("hwbuffer-size", m_HWBufferSize);
+ c->writeEntry("buffer-size", m_BufferSize);
+ c->writeEntry("soundstreamclient-id", m_SoundStreamClientID);
+
+ c->writeEntry("mixer-settings", m_CaptureMixerSettings.count());
+ int i = 0;
+ for (QMapConstIterator<QString, AlsaConfigMixerSetting> it = m_CaptureMixerSettings.begin(); it != m_CaptureMixerSettings.end(); ++it, ++i) {
+
+ QString prefix = QString("mixer-setting-%1-").arg(i);
+ (*it).saveState(c, prefix);
+ }
+
+}
+
+
+void AlsaSoundDevice::restoreState (KConfig *c)
+{
+ c->setGroup(QString("alsa-sound-") + PluginBase::name());
+
+ m_EnablePlayback = c->readBoolEntry("enable-playback", true);
+ m_EnableCapture = c->readBoolEntry("enable-capture", true);
+ m_HWBufferSize = c->readNumEntry ("hwbuffer-size", 2048);
+ m_BufferSize = c->readNumEntry ("buffer-size", 16384);
+ int card = c->readNumEntry ("playback-card", 0);
+ int dev = c->readNumEntry ("playback-device", 0);
+ setPlaybackDevice(card, dev);
+ card = c->readNumEntry ("capture-card", 0);
+ dev = c->readNumEntry ("capture-device", 0);
+ setCaptureDevice(card, dev);
+
+ m_PlaybackBuffer.resize(m_BufferSize);
+ m_CaptureBuffer.resize(m_BufferSize);
+
+ setSoundStreamClientID(c->readEntry("soundstreamclient-id", getSoundStreamClientID()));
+
+ int n = c->readNumEntry("mixer-settings", 0);
+ for (int i = 0; i < n; ++i) {
+ QString prefix = QString("mixer-setting-%1-").arg(i);
+ AlsaConfigMixerSetting s(c, prefix);
+ m_CaptureMixerSettings.insert(s.getIDString(), s);
+ }
+
+ emit sigUpdateConfig();
+}
+
+
+ConfigPageInfo AlsaSoundDevice::createConfigurationPage()
+{
+ AlsaSoundConfiguration *conf = new AlsaSoundConfiguration(NULL, this);
+ QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig()));
+ return ConfigPageInfo (conf,
+ i18n("ALSA Sound"),
+ i18n("ALSA Sound Device Options"),
+ "kradio_alsa2");
+}
+
+
+AboutPageInfo AlsaSoundDevice::createAboutPage()
+{
+/* KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("ALSA Sound Plugin for KRadio"),
+ KAboutData::License_GPL,
+ "(c) 2005 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/kradio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed),
+ i18n("ALSA Sound"),
+ i18n("ALSA Sound"),
+ "kradio_alsa_sound"
+ );
+*/
+ return AboutPageInfo();
+}
+
+
+
+bool AlsaSoundDevice::preparePlayback(SoundStreamID id, const QString &channel, bool active_mode, bool start_immediately)
+{
+ if (id.isValid()) {
+ m_PlaybackStreams.insert(id, SoundStreamConfig(channel, active_mode));
+ if (start_immediately)
+ startPlayback(id);
+ return true;
+ // FIXME: what to do if stream is already playing?
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::prepareCapture(SoundStreamID id, const QString &channel)
+{
+ if (id.isValid()) {
+ m_CaptureStreams.insert(id, SoundStreamConfig(channel));
+ return true;
+ // FIXME: what to do if stream is already playing?
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::releasePlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id)) {
+ if (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ stopPlayback(id);
+ }
+ m_PlaybackStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::releaseCapture(SoundStreamID id)
+{
+ if (id.isValid() && m_CaptureStreams.contains(id)) {
+ if (m_CaptureStreamID == id) {
+ stopCapture(id);
+ }
+ m_CaptureStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::supportsPlayback() const
+{
+ return m_EnablePlayback;
+}
+
+
+bool AlsaSoundDevice::supportsCapture() const
+{
+ return m_EnableCapture;
+}
+
+
+bool AlsaSoundDevice::startPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id) && m_EnablePlayback) {
+
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ bool ok = false;
+ if (cfg.m_ActiveMode) {
+ if (!m_PlaybackStreamID.isValid()) {
+ m_PlaybackStreamID = id;
+ ok = true;
+ }
+ } else {
+ if (!m_PassivePlaybackStreams.contains(id))
+ m_PassivePlaybackStreams.append(id);
+ ok = true;
+ }
+
+ if (ok) {
+ openPlaybackMixerDevice();
+ if (cfg.m_Volume >= 0 && writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume, cfg.m_Muted)) {
+ notifyPlaybackVolumeChanged(id, cfg.m_Volume);
+ notifyMuted(id, cfg.m_Volume);
+ }
+ m_PlaybackPollingTimer.start(m_PlaybackLatency);
+ }
+
+ // error handling?
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::pausePlayback(SoundStreamID /*id*/)
+{
+ //return stopPlayback(id);
+ return false;
+}
+
+
+bool AlsaSoundDevice::stopPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id)) {
+
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ if (!cfg.m_ActiveMode) {
+ if (m_PassivePlaybackStreams.contains(id)) {
+/* float tmp = 0;
+ writePlaybackMixerVolume(cfg.m_Channel, tmp, true);*/
+ m_PassivePlaybackStreams.remove(id);
+ }
+ } else if (m_PlaybackStreamID == id) {
+ m_PlaybackStreamID = SoundStreamID::InvalidID;
+ m_PlaybackBuffer.clear();
+ closePlaybackDevice();
+ }
+
+ closePlaybackMixerDevice();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AlsaSoundDevice::isPlaybackRunning(SoundStreamID id, bool &b) const
+{
+ if (id.isValid() && m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ b = true;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AlsaSoundDevice::startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format)
+{
+ if (m_CaptureStreams.contains(id) && m_EnableCapture) {
+
+ if (m_CaptureStreamID != id) {
+ m_CapturePos = 0;
+ m_CaptureStartTime = time(NULL);
+ }
+
+ if (m_CaptureStreamID != id || (force_format && proposed_format != m_CaptureFormat)) {
+
+ m_CaptureStreamID = id;
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ openCaptureMixerDevice();
+ selectCaptureChannel(cfg.m_Channel);
+ if (cfg.m_Volume >= 0 && writeCaptureMixerVolume(cfg.m_Channel, cfg.m_Volume)) {
+ notifyCaptureVolumeChanged(m_CaptureStreamID, cfg.m_Volume);
+ }
+
+ openCaptureDevice(proposed_format);
+
+ // FIXME: error handling?
+ }
+
+ real_format = m_CaptureFormat;
+ m_CaptureRequestCounter++;
+
+// m_captureThread = new AlsaCaptureThread(this, m_hCapture, m_CaptureFormat, 5, m_BufferSize);
+// m_captureThread->start();
+
+ slotPollCapture();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::stopCapture(SoundStreamID id)
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+
+ if (--m_CaptureRequestCounter == 0) {
+
+// m_captureThread->setDone();
+// if (!m_captureThread->wait(4000)) { //wait at maximum 4 seconds
+// logError("AlsaPlugin: capture thread did not terminate. Killing it.");
+// m_captureThread->terminate();
+// m_captureThread->wait();
+// }
+
+ slotPollCapture();
+
+// if (m_captureThread->error()) {
+// logError(i18n("ALSA Plugin, device plughw:%1,%2: %3").arg(m_CaptureCard)
+// .arg(m_CaptureDevice)
+// .arg(i18n("unknown error")));
+// }
+//
+// delete m_captureThread;
+// m_captureThread = NULL;
+
+ m_CaptureStreamID = SoundStreamID::InvalidID;
+ m_CaptureBuffer.clear();
+
+ closeCaptureMixerDevice();
+ closeCaptureDevice();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ b = true;
+ sf = m_CaptureFormat;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::noticeSoundStreamClosed(SoundStreamID id)
+{
+ bool found = false;
+ if (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ stopPlayback(id);
+ found = true;
+ }
+ if (m_CaptureStreamID == id) {
+ stopCapture(id);
+ found = true;
+ }
+ m_PlaybackStreams.remove(id);
+ m_CaptureStreams.remove(id);
+ return found;
+}
+
+
+bool AlsaSoundDevice::noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID)
+{
+ bool found = false;
+ if (m_PlaybackStreams.contains(oldID)) {
+ m_PlaybackStreams.insert(newID, m_PlaybackStreams[oldID]);
+ if (newID != oldID)
+ m_PlaybackStreams.remove(oldID);
+ found = true;
+ }
+ if (m_CaptureStreams.contains(oldID)) {
+ m_CaptureStreams.insert(newID, m_CaptureStreams[oldID]);
+ if (newID != oldID)
+ m_CaptureStreams.remove(oldID);
+ found = true;
+ }
+
+ if (m_PlaybackStreamID == oldID)
+ m_PlaybackStreamID = newID;
+ if (m_CaptureStreamID == oldID)
+ m_CaptureStreamID = newID;
+ if (m_PassivePlaybackStreams.contains(oldID)) {
+ m_PassivePlaybackStreams.remove(oldID);
+ m_PassivePlaybackStreams.append(newID);
+ }
+ return found;
+}
+
+
+bool AlsaSoundDevice::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &format,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &/*md*/
+ )
+{
+ if (!id.isValid() || id != m_PlaybackStreamID)
+ return false;
+
+ if (!m_hPlayback) {
+ openPlaybackDevice(format);
+ } else if (format != m_PlaybackFormat) {
+ // flush playback buffer
+ size_t buffersize = 0;
+ char *buffer = m_PlaybackBuffer.getData(buffersize);
+
+ snd_pcm_writei(m_hPlayback, buffer, buffersize / m_PlaybackFormat.sampleSize());
+
+ // if not all could be written, it must be discarded
+ m_PlaybackBuffer.clear();
+ closePlaybackDevice();
+ openPlaybackDevice(format);
+ // error handling ?
+ }
+
+ size_t n = m_PlaybackBuffer.addData(data, size);
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? n : min (consumed_size, n);
+/* if (n < size) {
+ m_PlaybackSkipCount += size - n;
+ } else if (m_PlaybackSkipCount > 0) {
+ logWarning(i18n("plughw:%1,%2: Playback buffer overflow. Skipped %3 bytes").arg(m_PlaybackCard).arg(m_PlaybackDevice).arg(QString::number(m_PlaybackSkipCount)));
+ m_PlaybackSkipCount = 0;
+ }
+ return m_PlaybackSkipCount == 0;*/
+ return true;
+}
+
+
+
+void AlsaSoundDevice::slotPollPlayback()
+{
+ if (m_PlaybackStreamID.isValid()) {
+
+ if (m_PlaybackBuffer.getFillSize() > 0 && m_hPlayback) {
+
+ size_t buffersize = 0;
+ int frameSize = m_CaptureFormat.frameSize();
+ char *buffer = m_PlaybackBuffer.getData(buffersize);
+ int framesWritten = snd_pcm_writei(m_hPlayback, buffer, buffersize / frameSize);
+ int bytesWritten = framesWritten * frameSize;
+
+ if (framesWritten > 0) {
+ m_PlaybackBuffer.removeData(bytesWritten);
+ } else if (framesWritten == 0) {
+ logError(i18n("ALSA Plugin: cannot write data for device plughw:%1,%2").arg(m_PlaybackCard).arg(m_PlaybackDevice));
+ } else if (framesWritten == -EAGAIN) {
+ // do nothing
+ } else {
+ snd_pcm_prepare(m_hPlayback);
+ logWarning(i18n("ALSA Plugin: buffer underrun for device plughw:%1,%2").arg(m_PlaybackCard).arg(m_PlaybackDevice));
+ }
+ }
+
+ if (m_PlaybackBuffer.getFreeSize() > m_PlaybackBuffer.getSize() / 3) {
+ notifyReadyForPlaybackData(m_PlaybackStreamID, m_PlaybackBuffer.getFreeSize());
+ }
+
+ checkMixerVolume(m_PlaybackStreamID);
+ }
+
+ QValueListConstIterator<SoundStreamID> end = m_PassivePlaybackStreams.end();
+ for (QValueListConstIterator<SoundStreamID> it = m_PassivePlaybackStreams.begin(); it != end; ++it)
+ checkMixerVolume(*it);
+}
+
+
+void AlsaSoundDevice::slotPollCapture()
+{
+ if (m_CaptureStreamID.isValid() && m_hCapture) {
+
+// while (m_captureThread && m_captureThread->getAvailableReadBuffers()) {
+// QString dev = QString("alsa://plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice);
+// size_t size = 0;
+// char *buffer = m_captureThread->getReadBuffer(size);
+// time_t cur_time = time(NULL);
+// notifySoundStreamData(m_CaptureStreamID, m_CaptureFormat, buffer, size, SoundMetaData(m_CapturePos, cur_time - m_CaptureStartTime, cur_time, dev));
+// m_CapturePos += size;
+// }
+
+ size_t bufferSize = 0;
+ char *buffer = m_CaptureBuffer.getFreeSpace(bufferSize);
+
+ if (bufferSize) {
+
+ size_t frameSize = m_CaptureFormat.frameSize();
+ int framesRead = snd_pcm_readi(m_hCapture, buffer, bufferSize / frameSize);
+ size_t bytesRead = framesRead > 0 ? framesRead * frameSize : 0;
+
+// //BEGIN DEBUG
+// static unsigned int debug_val = 0;
+// short *debug_buf = (short*)buffer;
+// for (int i = 0; i < bytesRead / 2 / sizeof(short); ++i) {
+// debug_buf[2*i] = debug_val >> 10;
+// debug_buf[2*i+1] = debug_val >> 10;
+// ++debug_val;
+// }
+// //END DEBUG
+
+ if (framesRead > 0) {
+ m_CaptureBuffer.removeFreeSpace(bytesRead);
+ } else if (framesRead == 0) {
+ snd_pcm_prepare(m_hCapture);
+ logError(i18n("ALSA Plugin: cannot read data from device plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice));
+ } else if (framesRead == -EAGAIN) {
+ // do nothing
+ } else {
+ snd_pcm_prepare(m_hCapture);
+ logWarning(i18n("ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer=%4)").arg(m_CaptureCard).arg(m_CaptureDevice).arg(bufferSize).arg((long long unsigned)buffer));
+ }
+
+ QString dev = QString("alsa://plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice);
+ while (m_CaptureBuffer.getFillSize() > m_CaptureBuffer.getSize() / 3) {
+ size_t size = 0;
+ buffer = m_CaptureBuffer.getData(size);
+ time_t cur_time = time(NULL);
+ size_t consumed_size = SIZE_T_DONT_CARE;
+
+ notifySoundStreamData(m_CaptureStreamID, m_CaptureFormat, buffer, size, consumed_size, SoundMetaData(m_CapturePos, cur_time - m_CaptureStartTime, cur_time, i18n("internal stream, not stored (%1)").arg(dev)));
+
+ if (consumed_size == SIZE_T_DONT_CARE)
+ consumed_size = size;
+ m_CaptureBuffer.removeData(consumed_size);
+ m_CapturePos += consumed_size;
+ if (consumed_size < size)
+ break;
+ }
+ }
+ }
+ if (m_CaptureStreamID.isValid())
+ checkMixerVolume(m_CaptureStreamID);
+}
+
+
+bool AlsaSoundDevice::openPlaybackDevice(const SoundFormat &format, bool reopen)
+{
+ if (m_PlaybackCard < 0 || m_PlaybackDevice < 0)
+ return false;
+
+ if (m_hPlayback) {
+
+ if (reopen) {
+
+ closePlaybackDevice ( /* force = */ true);
+
+ } else {
+
+ if (format != m_PlaybackFormat)
+ return false;
+
+ return true;
+ }
+ } else {
+ if (reopen) // FIXME: emw: please check if this makes sense !?!?
+ return true;
+ }
+
+ m_PlaybackFormat = format;
+
+ QString dev = QString("plughw:%1,%2").arg(m_PlaybackCard).arg(m_PlaybackDevice);
+ bool error = !openAlsaDevice(m_hPlayback, m_PlaybackFormat, dev.ascii(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK, m_PlaybackLatency);
+
+ if (!error) {
+ m_PlaybackPollingTimer.start(m_PlaybackLatency);
+ } else {
+ closePlaybackDevice();
+ }
+
+// m_PlaybackSkipCount = 0;
+
+ return !error;
+}
+
+
+bool AlsaSoundDevice::openCaptureDevice(const SoundFormat &format, bool reopen)
+{
+ if (m_PlaybackCard < 0 || m_PlaybackDevice < 0)
+ return false;
+
+ if (m_hCapture) {
+
+ if (reopen) {
+
+ closeCaptureDevice ( /* force = */ true);
+
+ } else {
+
+ if (format != m_CaptureFormat)
+ return false;
+
+ return true;
+ }
+ } else {
+ if (reopen) // FIXME: emw: please check if this makes sense !?!?
+ return true;
+ }
+
+ m_CaptureFormat = format;
+
+ QString dev = QString("plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice);
+// bool error = !openAlsaDevice(m_hCapture, m_CaptureFormat, dev.ascii(), SND_PCM_STREAM_CAPTURE, /*flags = block*/0, m_CaptureLatency);
+ bool error = !openAlsaDevice(m_hCapture, m_CaptureFormat, dev.ascii(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK, m_CaptureLatency);
+
+ if (!error) {
+ m_CapturePollingTimer.start(m_CaptureLatency);
+ } else {
+ closeCaptureDevice();
+ }
+
+ m_CaptureSkipCount = 0;
+
+ return !error;
+}
+
+
+bool AlsaSoundDevice::openAlsaDevice(snd_pcm_t *&alsa_handle, SoundFormat &format, const char *pcm_name, snd_pcm_stream_t stream, int flags, unsigned &latency)
+{
+ bool error = false;
+ int dir = 0;
+
+ snd_pcm_hw_params_t *hwparams = NULL;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+
+
+ /* OPEN */
+
+ if (!error && snd_pcm_open(&alsa_handle, pcm_name, stream, flags) < 0) {
+ logError(i18n("ALSA Plugin: Error opening PCM device %1").arg(pcm_name));
+ error = true;
+ }
+
+ if (!error && snd_pcm_hw_params_any(alsa_handle, hwparams) < 0) {
+ logError(i18n("ALSA Plugin: Can not configure PCM device %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* interleaved access type */
+
+ if (!error && snd_pcm_hw_params_set_access(alsa_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
+ logError(i18n("ALSA Plugin: Error setting access for %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* sample format */
+ snd_pcm_format_t sample_format = snd_pcm_build_linear_format(format.m_SampleBits,
+ format.m_SampleBits,
+ !format.m_IsSigned,
+ format.m_Endianess == BIG_ENDIAN);
+ if (!error && snd_pcm_hw_params_set_format(alsa_handle, hwparams, sample_format) < 0) {
+ logError(i18n("ALSA Plugin: Error setting sample format for %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* channels */
+ if (!error && snd_pcm_hw_params_set_channels(alsa_handle, hwparams, format.m_Channels) < 0) {
+ logError(i18n("ALSA Plugin: Error setting channels for %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* sample rate */
+ int rate = format.m_SampleRate;
+ if (!error && snd_pcm_hw_params_set_rate_near(alsa_handle, hwparams, &format.m_SampleRate, &dir) < 0) {
+ logError(i18n("ALSA Plugin: Error setting rate for %1").arg(pcm_name));
+ error = true;
+ }
+ if (!error && format.m_SampleRate != format.m_SampleRate) {
+ logWarning(i18n("ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 Hz instead").arg(rate).arg(pcm_name).arg(format.m_SampleRate));
+ }
+
+
+ snd_pcm_uframes_t period_size = m_HWBufferSize / format.frameSize();
+ if (!error && snd_pcm_hw_params_set_period_size_near(alsa_handle, hwparams, &period_size, &dir) < 0) {
+ logError(i18n("ALSA Plugin: Error setting period size for %1").arg(pcm_name));
+ error = true;
+ }
+
+// size_t buffersize_frames = m_HWBufferSize / format.frameSize();
+// int periods = 4;
+// //int period_size = m_BufferSize / periods;
+//
+// /* fragments */
+// if (!error && snd_pcm_hw_params_set_periods(alsa_handle, hwparams, periods, 0) < 0) {
+// logError(i18n("ALSA Plugin: Error setting periods for %1").arg(pcm_name));
+// error = true;
+// }
+
+// /* Set buffer size (in frames). */
+//
+// snd_pcm_uframes_t exact_buffersize_frames = buffersize_frames;
+// if (!error && snd_pcm_hw_params_set_buffer_size_near(alsa_handle, hwparams, &exact_buffersize_frames) < 0) {
+// exact_buffersize_frames = 4096;
+// if (!error && snd_pcm_hw_params_set_buffer_size_near(alsa_handle, hwparams, &exact_buffersize_frames) < 0) {
+// logError(i18n("ALSA Plugin: Error setting buffersize for %1").arg(pcm_name));
+// error = true;
+// }
+// }
+
+// size_t exact_buffersize = exact_buffersize_frames * format.frameSize();
+// if (!error && m_HWBufferSize != exact_buffersize) {
+// logWarning(i18n("ALSA Plugin: Hardware %1 does not support buffer size of %2. Using buffer size of %3 instead.").arg(pcm_name).arg(m_HWBufferSize).arg(exact_buffersize));
+// size_t tmp = (((m_HWBufferSize - 1) / exact_buffersize) + 1) * exact_buffersize;
+// setHWBufferSize(tmp);
+// logInfo(i18n("ALSA Plugin: adjusted buffer size for %1 to %2 bytes").arg(pcm_name).arg(QString::number(tmp)));
+// }
+
+ /* set all params */
+
+ if (!error && snd_pcm_hw_params(alsa_handle, hwparams) < 0) {
+ logError(i18n("ALSA Plugin: Error setting HW params"));
+ error = true;
+ }
+
+ if (!error && snd_pcm_hw_params_get_period_size(hwparams, &period_size, &dir) < 0) {
+ logError(i18n("ALSA Plugin: Error getting period size for %1").arg(pcm_name));
+ error = true;
+ }
+
+// latency = (exact_buffersize_frames * 1000) / format.m_SampleRate / periods; /* in milli seconds */
+ latency = (period_size * format.frameSize() * 1000) / format.m_SampleRate; /* in milli seconds */
+
+ if (!error) {
+ snd_pcm_prepare(alsa_handle);
+ }
+
+ return !error;
+}
+
+
+bool AlsaSoundDevice::closePlaybackDevice(bool force)
+{
+ if (!m_PlaybackStreamID.isValid() || force) {
+
+ if (!m_hPlaybackMixer)
+ m_PlaybackPollingTimer.stop();
+
+ if (m_hPlayback) {
+ snd_pcm_drop(m_hPlayback);
+ snd_pcm_close(m_hPlayback);
+ }
+
+ m_hPlayback = NULL;
+
+ m_PlaybackBuffer.clear();
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::closeCaptureDevice(bool force)
+{
+ if (!m_CaptureStreamID.isValid() || force) {
+
+ if (!m_hCaptureMixer)
+ m_CapturePollingTimer.stop();
+
+ if (m_hCapture) {
+ snd_pcm_drop(m_hCapture);
+ snd_pcm_close(m_hCapture);
+ }
+
+ m_hCapture = NULL;
+
+ m_CaptureBuffer.clear();
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::openPlaybackMixerDevice(bool reopen)
+{
+ return openMixerDevice(m_hPlaybackMixer, m_PlaybackCard, reopen, &m_PlaybackPollingTimer, m_PlaybackLatency);
+}
+
+
+bool AlsaSoundDevice::openCaptureMixerDevice(bool reopen)
+{
+// logDebug("AlsaSoundDevice::openCaptureMixerDevice: card == " + QString::number(m_CaptureCard));
+ return openMixerDevice(m_hCaptureMixer, m_CaptureCard, reopen, &m_CapturePollingTimer, m_CaptureLatency);
+}
+
+
+bool AlsaSoundDevice::closePlaybackMixerDevice(bool force)
+{
+ return closeMixerDevice(m_hPlaybackMixer, m_PlaybackCard, m_PlaybackStreamID, m_hPlayback, force, &m_PlaybackPollingTimer);
+}
+
+bool AlsaSoundDevice::closeCaptureMixerDevice(bool force)
+{
+ return closeMixerDevice(m_hCaptureMixer, m_CaptureCard, m_CaptureStreamID, m_hCapture, force, &m_CapturePollingTimer);
+}
+
+
+static int mixer_dummy_callback(snd_mixer_t *, unsigned int /*mask*/, snd_mixer_elem_t */*elem*/)
+{
+ return 0;
+}
+
+bool AlsaSoundDevice::openMixerDevice(snd_mixer_t *&mixer_handle, int card, bool reopen, QTimer *timer, int timer_latency)
+{
+ if (reopen) {
+ if (mixer_handle >= 0)
+ closeMixerDevice(mixer_handle, card, SoundStreamID::InvalidID, NULL, /* force = */ true, timer);
+ else
+ return true;
+ }
+
+ if (!mixer_handle) {
+ bool error = false;
+ if (snd_mixer_open (&mixer_handle, 0) < 0) {
+ staticLogError(i18n("ALSA Plugin: Error opening mixer"));
+ error = true;
+ }
+ QString cardid = "hw:" + QString::number(card);
+ bool attached = false;
+ if (!error) {
+ if (snd_mixer_attach (mixer_handle, cardid.ascii()) < 0) {
+ staticLogError(i18n("ALSA Plugin: ERROR: snd_mixer_attach for card %1").arg(card));
+ error = true;
+ } else {
+ attached = true;
+ }
+ }
+ if (!error && snd_mixer_selem_register(mixer_handle, NULL, NULL) < 0) {
+ staticLogError(i18n("ALSA Plugin: Error: snd_mixer_selem_register for card %1").arg(card));
+ error = true;
+ }
+ if (!error && snd_mixer_load (mixer_handle) < 0) {
+ staticLogError(i18n("ALSA Plugin: Error: snd_mixer_load for card %1").arg(card));
+ error = true;
+ }
+ if (mixer_handle) {
+ snd_mixer_set_callback (mixer_handle, mixer_dummy_callback);
+ }
+
+ if (error) {
+ if (attached) {
+ snd_mixer_detach(mixer_handle, cardid.ascii());
+ }
+ snd_mixer_close(mixer_handle);
+ mixer_handle = NULL;
+ }
+ }
+
+ if (mixer_handle && timer) {
+ timer->start(timer_latency);
+ }
+ return mixer_handle != NULL;
+}
+
+
+bool AlsaSoundDevice::closeMixerDevice(snd_mixer_t *&mixer_handle, int card, SoundStreamID id, snd_pcm_t *pcm_handle, bool force, QTimer *timer)
+{
+ if (!id.isValid() || force) {
+
+ if (!pcm_handle && timer)
+ timer->stop();
+
+ if (mixer_handle) {
+ QString cardid = "hw:" + QString::number(card);
+ snd_mixer_free(mixer_handle);
+ snd_mixer_detach(mixer_handle, cardid.ascii());
+ snd_mixer_close (mixer_handle);
+ }
+ mixer_handle = NULL;
+ }
+ return mixer_handle == NULL;
+}
+
+void AlsaSoundDevice::getPlaybackMixerChannels(
+ int card,
+ snd_mixer_t *__mixer_handle,
+ QStringList &retval, QMap<QString, AlsaMixerElement> &ch2id)
+{
+ retval.clear();
+ ch2id.clear();
+
+ snd_mixer_t *mixer_handle = __mixer_handle/*m_hPlaybackMixer*/;
+ bool use_tmp_handle = false;
+
+ if (!mixer_handle) {
+ openMixerDevice(mixer_handle, card/*m_PlaybackCard*/, false, NULL, 0);
+ use_tmp_handle = true;
+ }
+
+ if (mixer_handle) {
+ snd_mixer_elem_t *elem = NULL;
+
+ for (elem = snd_mixer_first_elem(mixer_handle); elem; elem = snd_mixer_elem_next(elem)) {
+ AlsaMixerElement sid;
+ if (!snd_mixer_selem_is_active(elem))
+ continue;
+ snd_mixer_selem_get_id(elem, sid);
+ QString name = snd_mixer_selem_id_get_name(sid);
+ int idx = snd_mixer_selem_id_get_index(sid);
+ if (idx)
+ name = i18n("context-mixername-number", "%1 %2").arg(name).arg(idx);
+ if (snd_mixer_selem_has_playback_volume(elem)) {
+ ch2id[name] = sid;
+ retval.append(name);
+ }
+ }
+ }
+
+ if (use_tmp_handle && mixer_handle) {
+ closeMixerDevice(mixer_handle, card /*m_PlaybackCard*/, SoundStreamID::InvalidID, NULL, true, NULL);
+ }
+}
+
+void AlsaSoundDevice::getCaptureMixerChannels(
+ int card,
+ snd_mixer_t *__mixer_handle,
+ QStringList &vol_list, QMap<QString, AlsaMixerElement> &vol_ch2id,
+ QStringList &sw_list, QMap<QString, AlsaMixerElement> &sw_ch2id,
+ QStringList *all_list
+)
+{
+ vol_list.clear();
+ sw_list.clear();
+ if (all_list) all_list->clear();
+ vol_ch2id.clear();
+ sw_ch2id.clear();
+
+ snd_mixer_t *mixer_handle = __mixer_handle /*m_hCaptureMixer*/;
+ bool use_tmp_handle = false;
+
+ if (!mixer_handle) {
+// staticLogDebug("AlsaSoundDevice::getCaptureMixerChannels: card == " + QString::number(card/*m_CaptureCard*/));
+ openMixerDevice(mixer_handle, card /*m_CaptureCard*/, false, NULL, 0);
+ use_tmp_handle = true;
+ }
+
+ if (mixer_handle) {
+ snd_mixer_elem_t *elem = NULL;
+
+ for (elem = snd_mixer_first_elem(mixer_handle); elem; elem = snd_mixer_elem_next(elem)) {
+ AlsaMixerElement sid;
+ if (!snd_mixer_selem_is_active(elem))
+ continue;
+ snd_mixer_selem_get_id(elem, sid);
+ QString name = snd_mixer_selem_id_get_name(sid);
+ int idx = snd_mixer_selem_id_get_index(sid);
+ if (idx)
+ name = i18n("context-mixerelement-name-number", "%1 %2").arg(name).arg(idx);
+
+ bool add2all = false;
+ if (snd_mixer_selem_has_capture_switch(elem)) {
+ sw_ch2id[name] = sid;
+ sw_list.append(name);
+ add2all = true;
+ }
+ if (snd_mixer_selem_has_capture_volume(elem)) {
+ vol_ch2id[name] = sid;
+ vol_list.append(name);
+ add2all = true;
+ }
+ if (add2all && all_list) {
+ all_list->append(name);
+ }
+ }
+ }
+
+ if (use_tmp_handle && mixer_handle) {
+ closeMixerDevice(mixer_handle, card /*m_CaptureCard*/, SoundStreamID::InvalidID, NULL, true, NULL);
+ }
+}
+
+const QStringList &AlsaSoundDevice::getPlaybackChannels() const
+{
+ return m_PlaybackChannels;
+}
+
+
+const QStringList &AlsaSoundDevice::getCaptureChannels() const
+{
+ return m_CaptureChannelsSwitch;
+}
+
+
+bool AlsaSoundDevice::setPlaybackVolume(SoundStreamID id, float volume)
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ if (rint(100*volume) != rint(100*cfg.m_Volume)) {
+ if (writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume = volume, cfg.m_Muted)) {
+ notifyPlaybackVolumeChanged(id, cfg.m_Volume);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::setCaptureVolume(SoundStreamID id, float volume)
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ if (rint(100*volume) != rint(100*cfg.m_Volume)) {
+ if (writeCaptureMixerVolume(cfg.m_Channel, cfg.m_Volume = volume)) {
+ notifyCaptureVolumeChanged(id, cfg.m_Volume);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::getPlaybackVolume(SoundStreamID id, float &volume) const
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ const SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ volume = cfg.m_Volume;
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::getCaptureVolume(SoundStreamID id, float &volume) const
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ const SoundStreamConfig &cfg = m_CaptureStreams[id];
+ volume = cfg.m_Volume;
+ return true;
+ }
+ return false;
+}
+
+
+void AlsaSoundDevice::checkMixerVolume(SoundStreamID id)
+{
+ if (id.isValid()) {
+
+ if (m_hPlaybackMixer && m_PassivePlaybackStreams.contains(id) || m_PlaybackStreamID == id) {
+ snd_mixer_handle_events(m_hPlaybackMixer);
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ bool m = false;
+ float v = readPlaybackMixerVolume(cfg.m_Channel, m);
+ if (rint(100*cfg.m_Volume) != rint(100*v)) {
+ cfg.m_Volume = v;
+ notifyPlaybackVolumeChanged(id, v);
+ }
+ if (m != cfg.m_Muted) {
+ cfg.m_Muted = m;
+ notifyMuted(id, m);
+ }
+ }
+
+ if (m_hCaptureMixer && m_CaptureStreamID == id) {
+ snd_mixer_handle_events(m_hCaptureMixer);
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ if (m_CaptureChannels2ID.contains(cfg.m_Channel)) {
+ float v = readCaptureMixerVolume(cfg.m_Channel);
+ if (rint(100*cfg.m_Volume) != rint(100*v)) {
+ cfg.m_Volume = v;
+ notifyCaptureVolumeChanged(id, v);
+ }
+ }
+ }
+ }
+}
+
+
+float AlsaSoundDevice::readPlaybackMixerVolume(const QString &channel, bool &muted) const
+{
+ if (!m_hPlaybackMixer)
+ return 0; // without error
+
+ if (m_PlaybackChannels2ID.contains(channel) && m_hPlaybackMixer) {
+ AlsaMixerElement sid = m_PlaybackChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hPlaybackMixer, sid);
+ if (elem) {
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = min;
+
+ muted = false;
+ int m = false;
+ if (snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, &m) == 0) {
+ muted = !m;
+ }
+ if (snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &val) == 0) {
+ return ((float)(val - min)) / (float)(max - min);
+ }
+ }
+ }
+ }
+ logError("AlsaSound::readPlaybackMixerVolume: " +
+ i18n("error while reading volume from hwplug:%1,%2")
+ .arg(m_PlaybackCard)
+ .arg(m_PlaybackDevice));
+ return 0;
+}
+
+
+float AlsaSoundDevice::readCaptureMixerVolume(const QString &channel) const
+{
+ if (!m_hCaptureMixer)
+ return 0; // without error
+
+ if (m_CaptureChannels2ID.contains(channel) && m_hCaptureMixer) {
+ AlsaMixerElement sid = m_CaptureChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hCaptureMixer, sid);
+ if (elem) {
+ if (!snd_mixer_selem_has_capture_volume(elem))
+ return 0;
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = min;
+ if (snd_mixer_selem_get_capture_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &val) == 0) {
+ return ((float)(val - min)) / (float)(max - min);
+ }
+ }
+ }
+ }
+ logError("AlsaSound::readCaptureMixerVolume: " +
+ i18n("error while reading volume from hwplug:%1,%2")
+ .arg(m_CaptureCard)
+ .arg(m_CaptureDevice));
+ return 0;
+}
+
+
+bool AlsaSoundDevice::writePlaybackMixerVolume (const QString &channel, float &vol, bool muted)
+{
+ if (vol > 1.0) vol = 1.0;
+ if (vol < 0) vol = 0.0;
+
+ if (!m_hPlaybackMixer)
+ return false;
+
+ if (m_PlaybackChannels2ID.contains(channel) && m_hPlaybackMixer) {
+ AlsaMixerElement sid = m_PlaybackChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hPlaybackMixer, sid);
+ if (elem) {
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = (int)rint(min + (max - min) * vol);
+ vol = (float)(val - min) / (float)(max - min);
+ snd_mixer_selem_set_playback_switch_all(elem, !muted);
+ if (snd_mixer_selem_set_playback_volume_all(elem, val) == 0) {
+ return true;
+ }
+ }
+ }
+ }
+ logError("AlsaSound::writePlaybackMixerVolume: " +
+ i18n("error while writing volume %1 to hwplug:%2,%3")
+ .arg(vol)
+ .arg(m_PlaybackCard)
+ .arg(m_PlaybackDevice));
+ return false;
+}
+
+
+
+
+bool AlsaSoundDevice::writeCaptureMixerVolume (const QString &channel, float &vol)
+{
+ if (vol > 1.0) vol = 1.0;
+ if (vol < 0) vol = 0.0;
+
+ if (!m_hCaptureMixer)
+ return false;
+
+ if (m_CaptureChannels2ID.contains(channel) && m_hCaptureMixer) {
+ AlsaMixerElement sid = m_CaptureChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hCaptureMixer, sid);
+ if (elem) {
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = (int)rint(min + (max - min) * vol);
+ vol = (float)(val - min) / (float)(max - min);
+ if (snd_mixer_selem_set_capture_volume_all(elem, val) == 0) {
+ return true;
+ }
+ }
+ }
+ }
+ logError("AlsaSound::writeCaptureMixerVolume: " +
+ i18n("error while writing volume %1 to hwplug:%2,%3")
+ .arg(vol)
+ .arg(m_CaptureCard)
+ .arg(m_CaptureDevice));
+ return false;
+}
+
+
+bool AlsaSoundDevice::writeCaptureMixerSwitch (const QString &channel, bool capture)
+{
+ if (!m_hCaptureMixer)
+ return false;
+
+ if (m_CaptureChannelsSwitch2ID.contains(channel) && m_hCaptureMixer) {
+ AlsaMixerElement sid = m_CaptureChannelsSwitch2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hCaptureMixer, sid);
+ if (elem) {
+ if (snd_mixer_selem_set_capture_switch_all(elem, capture) == 0) {
+ return true;
+ }
+ }
+ }
+ logError("AlsaSound::writeCaptureMixerSwitch: " +
+ i18n("error while setting capture switch %1 for hwplug:%2,%3")
+ .arg(channel)
+ .arg(m_CaptureCard)
+ .arg(m_CaptureDevice));
+ return false;
+}
+
+
+void AlsaSoundDevice::selectCaptureChannel (const QString &channel)
+{
+ writeCaptureMixerSwitch(channel, true);
+
+ const QString ADC = "ADC";
+ if (m_CaptureChannels2ID.contains(ADC)) {
+ float v = readCaptureMixerVolume(ADC);
+ if (rint(v*100) == 0) {
+ float tmp_vol = 1.0;
+ writeCaptureMixerVolume(ADC, tmp_vol);
+ }
+ }
+ const QString Digital = "Digital";
+ if (m_CaptureChannels2ID.contains(Digital)) {
+ float v = readCaptureMixerVolume(Digital);
+ if (rint(v*100) == 0) {
+ float tmp_vol = 1.0;
+ writeCaptureMixerVolume(Digital, tmp_vol);
+ }
+ }
+ const QString WAVE = "Wave";
+ if (m_CaptureChannels2ID.contains(WAVE)) {
+ float x = 0;
+ writeCaptureMixerVolume(WAVE, x);
+ }
+ const QString Capture = "Capture";
+ if (m_CaptureChannelsSwitch2ID.contains(Capture)) {
+ writeCaptureMixerSwitch(Capture, true);
+ }
+
+ for (QMapConstIterator<QString, AlsaConfigMixerSetting> it = m_CaptureMixerSettings.begin(); it != m_CaptureMixerSettings.end(); ++it) {
+ const AlsaConfigMixerSetting &s = *it;
+ if (s.m_card == m_CaptureCard && s.m_use) {
+ float vol = s.m_volume;
+ if (m_CaptureChannels2ID.contains(s.m_name))
+ writeCaptureMixerVolume(s.m_name, vol);
+ if (m_CaptureChannelsSwitch2ID.contains(s.m_name))
+ writeCaptureMixerSwitch(s.m_name, s.m_active);
+ }
+ }
+}
+
+
+void AlsaSoundDevice::setHWBufferSize(int s)
+{
+ m_HWBufferSize = s;
+}
+
+
+void AlsaSoundDevice::setBufferSize(int s)
+{
+ m_BufferSize = s;
+ m_PlaybackBuffer.resize(m_BufferSize);
+ m_CaptureBuffer.resize(m_BufferSize);
+}
+
+
+void AlsaSoundDevice::enablePlayback(bool on)
+{
+ m_EnablePlayback = on;
+}
+
+
+void AlsaSoundDevice::enableCapture(bool on)
+{
+ m_EnableCapture = on;
+}
+
+
+void AlsaSoundDevice::setPlaybackDevice(int card, int dev)
+{
+ if (m_PlaybackCard == card && m_PlaybackDevice == dev)
+ return;
+
+ m_PlaybackCard = card;
+ m_PlaybackDevice = dev;
+ SoundFormat f = m_PlaybackFormat;
+ if (m_hPlayback)
+ openPlaybackDevice(f, /* reopen = */ true);
+ if (m_hPlaybackMixer)
+ openPlaybackMixerDevice(/* reopen = */ true);
+
+ getPlaybackMixerChannels(m_PlaybackCard,
+ m_hPlaybackMixer,
+ m_PlaybackChannels, m_PlaybackChannels2ID);
+ notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannels);
+}
+
+
+void AlsaSoundDevice::setCaptureDevice(int card, int dev)
+{
+// logDebug("AlsaSoundDevice::setCaptureDevice-1: m_CaptureCard == " + QString::number(m_CaptureCard) + ", card == " + QString::number(card));
+ if (m_CaptureCard == card && m_CaptureDevice == dev)
+ return;
+// logDebug("AlsaSoundDevice::setCaptureDevice-2: m_CaptureCard == " + QString::number(m_CaptureCard) + ", card == " + QString::number(card));
+
+ m_CaptureCard = card;
+ m_CaptureDevice = dev;
+ SoundFormat f = m_CaptureFormat;
+ if (m_hCapture)
+ openCaptureDevice(f, /* reopen = */ true);
+ if (m_hCaptureMixer)
+ openCaptureMixerDevice(/* reopen = */ true);
+
+ getCaptureMixerChannels(m_CaptureCard,
+ m_hCaptureMixer,
+ m_CaptureChannels, m_CaptureChannels2ID, m_CaptureChannelsSwitch, m_CaptureChannelsSwitch2ID);
+ notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannels);
+}
+
+
+QString AlsaSoundDevice::getSoundStreamClientDescription() const
+{
+ return i18n("ALSA Sound Device %1").arg(PluginBase::name());
+}
+
+
+bool AlsaSoundDevice::mute (SoundStreamID id, bool mute)
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ if (mute != cfg.m_Muted) {
+ if (writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume, cfg.m_Muted = mute)) {
+ notifyMuted(id, cfg.m_Muted);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::unmute (SoundStreamID id, bool unmute)
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ bool mute = !unmute;
+ if (mute != cfg.m_Muted) {
+ if (writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume, cfg.m_Muted = mute)) {
+ notifyMuted(id, cfg.m_Muted);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::isMuted(SoundStreamID id, bool &m) const
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ const SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ m = cfg.m_Muted;
+ return true;
+ }
+ return false;
+}
+
+
+void AlsaSoundDevice::setCaptureMixerSettings(const QMap<QString, AlsaConfigMixerSetting> &map)
+{
+ m_CaptureMixerSettings = map;
+}
+
+
+
+// bool AlsaSoundDevice::event(QEvent *_e)
+// {
+// bool retval = false;
+//
+// switch (_e->type()) {
+//
+// case CaptureTerminated :
+// retval = true;
+// break;
+//
+// case CaptureStep :
+//
+// slotPollCapture();
+//
+// retval = true;
+// break;
+//
+// case CaptureError :
+// case CaptureWarning :
+// case CaptureInfo :
+// case CaptureDebug :
+// if (m_captureThread) {
+// AlsaCaptureEvent *e = static_cast<AlsaCaptureEvent*>(_e);
+// QString msg = i18n("ALSA Plugin, device plughw:%1,%2: %3")
+// .arg(m_CaptureCard)
+// .arg(m_CaptureDevice)
+// .arg(e->message());
+// switch (_e->type()) {
+// case CaptureError :
+// logError(msg);
+// m_captureThread->resetError();
+// break;
+// case CaptureWarning :
+// logWarning(msg);
+// break;
+// case CaptureInfo :
+// logInfo(msg);
+// break;
+// case CaptureDebug :
+// logDebug(msg);
+// break;
+// default:
+// break;
+// }
+// }
+// retval = true;
+// break;
+//
+// default:
+// retval = QObject::event(_e);
+// break;
+// }
+//
+// return retval;
+// }
+
+
+
+
+
+
+
+
+#include "alsa-sound.moc"
diff --git a/kradio3/plugins/alsa-sound/alsa-sound.h b/kradio3/plugins/alsa-sound/alsa-sound.h
new file mode 100644
index 0000000..93a9fc8
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/alsa-sound.h
@@ -0,0 +1,296 @@
+/***************************************************************************
+ alsa-sound.h - description
+ -------------------
+ begin : Thu May 26 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KRADIO_ALSA_SOUND_H
+#define _KRADIO_ALSA_SOUND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/ringbuffer.h"
+#include "../../src/include/plugins.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+#include "alsa-config-mixer-setting.h"
+
+#include <qobject.h>
+#include <qtimer.h>
+#include <alsa/asoundlib.h>
+
+enum DUPLEX_MODE { DUPLEX_UNKNOWN, DUPLEX_FULL, DUPLEX_HALF };
+
+
+struct SoundStreamConfig
+{
+ SoundStreamConfig()
+ : m_ActiveMode(false),
+ m_Channel(QString::null),
+ m_Volume(-1),
+ m_Muted(false)
+ {}
+
+ SoundStreamConfig(const QString &_channel, bool active_mode = true)
+ : m_ActiveMode(active_mode),
+ m_Channel(_channel),
+ m_Volume(-1),
+ m_Muted(false)
+ {}
+
+ SoundStreamConfig(const SoundStreamConfig &c)
+ : m_ActiveMode(c.m_ActiveMode),
+ m_Channel(c.m_Channel),
+ m_Volume(c.m_Volume),
+ m_Muted(c.m_Muted)
+ {}
+
+ bool m_ActiveMode;
+ QString m_Channel;
+ float m_Volume;
+ bool m_Muted;
+};
+
+
+class AlsaCaptureThread;
+
+class AlsaMixerElement
+{
+public:
+ AlsaMixerElement() { snd_mixer_selem_id_malloc(&m_ID); }
+ AlsaMixerElement(snd_mixer_selem_id_t *id) { snd_mixer_selem_id_malloc(&m_ID); snd_mixer_selem_id_copy(m_ID, id) ; }
+ AlsaMixerElement(const AlsaMixerElement &x) { snd_mixer_selem_id_malloc(&m_ID); snd_mixer_selem_id_copy(m_ID, x.m_ID); }
+ ~AlsaMixerElement() { snd_mixer_selem_id_free (m_ID); }
+
+ operator snd_mixer_selem_id_t *&() { return m_ID; }
+
+ AlsaMixerElement &operator = (const AlsaMixerElement &x) { snd_mixer_selem_id_copy(m_ID, x.m_ID); return *this; }
+
+protected:
+ snd_mixer_selem_id_t *m_ID;
+};
+
+
+class AlsaSoundDevice : public QObject,
+ public PluginBase,
+ public ISoundStreamClient
+{
+Q_OBJECT
+
+public:
+ AlsaSoundDevice (const QString &name);
+ virtual ~AlsaSoundDevice ();
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual QString pluginClassName() const { return "AlsaSoundDevice"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // ISoundStreamClient: direct device access
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+ bool preparePlayback(SoundStreamID id, const QString &channel, bool active_mode, bool start_immediately);
+ bool prepareCapture(SoundStreamID id, const QString &channel);
+ bool releasePlayback(SoundStreamID id);
+ bool releaseCapture(SoundStreamID id);
+
+ANSWERS:
+ bool supportsPlayback() const;
+ bool supportsCapture() const;
+
+ QString getSoundStreamClientDescription() const;
+
+ // ISoundStreamClient: mixer access
+
+public:
+ static
+ void getPlaybackMixerChannels(int card, snd_mixer_t *mixer_handle,
+ QStringList &retval, QMap<QString, AlsaMixerElement> &int2id);
+ static
+ void getCaptureMixerChannels (int card, snd_mixer_t *mixer_handle,
+ QStringList &vol_list, QMap<QString, AlsaMixerElement> &vol_ch2id,
+ QStringList &sw_list, QMap<QString, AlsaMixerElement> &sw_ch2id,
+ QStringList *all_list = NULL);
+
+ANSWERS:
+ const QStringList &getPlaybackChannels() const;
+ const QStringList &getCaptureChannels() const;
+
+RECEIVERS:
+ bool setPlaybackVolume(SoundStreamID id, float volume);
+ bool setCaptureVolume(SoundStreamID id, float volume);
+ bool getPlaybackVolume(SoundStreamID id, float &volume) const;
+ bool getCaptureVolume(SoundStreamID id, float &volume) const;
+
+ bool mute (SoundStreamID id, bool mute);
+ bool unmute (SoundStreamID id, bool unmute);
+ bool isMuted(SoundStreamID id, bool &m) const;
+
+
+ // ISoundStreamClient: generic broadcasts
+
+RECEIVERS:
+ bool startPlayback(SoundStreamID id);
+ bool pausePlayback(SoundStreamID id);
+ bool stopPlayback(SoundStreamID id);
+ bool isPlaybackRunning(SoundStreamID id, bool &b) const;
+
+ bool startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format);
+ bool stopCapture(SoundStreamID id);
+ bool isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const;
+
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID);
+
+ bool noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+ );
+
+
+ // Config Access
+
+ int getHWBufferSize() const { return m_HWBufferSize; }
+ int getBufferSize() const { return m_BufferSize; }
+ bool isPlaybackEnabled() const { return m_EnablePlayback; }
+ bool isCaptureEnabled() const { return m_EnableCapture; }
+ int getPlaybackCard() const { return m_PlaybackCard; }
+ int getPlaybackDevice() const { return m_PlaybackDevice; }
+ int getCaptureCard() const { return m_CaptureCard; }
+ int getCaptureDevice() const { return m_CaptureDevice; }
+ const QMap<QString, AlsaConfigMixerSetting> &
+ getCaptureMixerSettings() const { return m_CaptureMixerSettings; }
+
+ void setHWBufferSize(int s);
+ void setBufferSize(int s);
+ void enablePlayback(bool on);
+ void enableCapture(bool on);
+ void setPlaybackDevice(int card, int device);
+ void setCaptureDevice(int card, int device);
+ void setCaptureMixerSettings(const QMap<QString, AlsaConfigMixerSetting> &map);
+
+protected slots:
+
+ void slotPollPlayback();
+ void slotPollCapture();
+
+signals:
+
+ void sigUpdateConfig();
+
+protected:
+// bool event(QEvent *_e);
+
+ bool openAlsaDevice(snd_pcm_t *&alsa_handle, SoundFormat &format, const char *pcm_name, snd_pcm_stream_t stream, int flags, unsigned &latency);
+
+ bool openPlaybackDevice (const SoundFormat &format, bool reopen = false);
+ bool openCaptureDevice (const SoundFormat &format, bool reopen = false);
+ bool closePlaybackDevice(bool force = false);
+ bool closeCaptureDevice (bool force = false);
+
+ bool openPlaybackMixerDevice (bool reopen = false);
+ bool openCaptureMixerDevice (bool reopen = false);
+ static bool openMixerDevice(snd_mixer_t *&mixer_handle, int card, bool reopen, QTimer *timer, int timer_latency);
+ bool closeCaptureMixerDevice (bool force = false);
+ bool closePlaybackMixerDevice(bool force = false);
+ static bool closeMixerDevice(snd_mixer_t *&mixer_handle, int card, SoundStreamID id, snd_pcm_t *pcm_handle, bool force, QTimer *timer);
+
+ void checkMixerVolume(SoundStreamID id);
+ float readPlaybackMixerVolume(const QString &channel, bool &muted) const;
+ float readCaptureMixerVolume(const QString &channel) const;
+ bool writePlaybackMixerVolume(const QString &channel, float &vol, bool muted);
+ bool writeCaptureMixerVolume(const QString &channel, float &vol);
+ bool writeCaptureMixerSwitch(const QString &channel, bool capture);
+
+ void selectCaptureChannel (const QString &channel);
+
+ /* ALSA HANDLES */
+ snd_pcm_t *m_hPlayback;
+ snd_pcm_t *m_hCapture;
+ snd_mixer_t *m_hPlaybackMixer;
+ snd_mixer_t *m_hCaptureMixer;
+
+ SoundFormat m_PlaybackFormat;
+ SoundFormat m_CaptureFormat;
+ int m_PlaybackCard;
+ int m_PlaybackDevice;
+ int m_CaptureCard;
+ int m_CaptureDevice;
+
+ unsigned m_PlaybackLatency;
+ unsigned m_CaptureLatency;
+
+ QStringList m_PlaybackChannels,
+ m_CaptureChannels,
+ m_CaptureChannelsSwitch;
+
+ QMap<QString, AlsaMixerElement> m_PlaybackChannels2ID,
+ m_CaptureChannels2ID,
+ m_CaptureChannelsSwitch2ID;
+
+ QMap<SoundStreamID, SoundStreamConfig>
+ m_PlaybackStreams,
+ m_CaptureStreams;
+
+ QValueList<SoundStreamID>
+ m_PassivePlaybackStreams;
+ SoundStreamID m_PlaybackStreamID,
+ m_CaptureStreamID;
+
+ size_t m_HWBufferSize;
+ size_t m_BufferSize;
+ RingBuffer m_PlaybackBuffer,
+ m_CaptureBuffer;
+
+ unsigned m_CaptureRequestCounter;
+ Q_UINT64 m_CapturePos;
+ time_t m_CaptureStartTime;
+
+ size_t //m_PlaybackSkipCount,
+ m_CaptureSkipCount;
+
+ bool m_EnablePlayback,
+ m_EnableCapture;
+
+ QTimer m_PlaybackPollingTimer;
+ QTimer m_CapturePollingTimer;
+
+// AlsaCaptureThread *m_captureThread;
+
+ QMap<QString, AlsaConfigMixerSetting> m_CaptureMixerSettings;
+
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/alsa-sound/icons/Makefile.am b/kradio3/plugins/alsa-sound/icons/Makefile.am
new file mode 100644
index 0000000..b3f2583
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/Makefile.am
@@ -0,0 +1,2 @@
+icons_ICON = AUTO
+iconsdir = $(kde_datadir)/kradio/icons
diff --git a/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa.png
new file mode 100644
index 0000000..a25cfd2
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa2.png
new file mode 100644
index 0000000..479a6cc
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa2.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa.png
new file mode 100644
index 0000000..796b052
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa2.png
new file mode 100644
index 0000000..5e6cc22
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa2.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa.png
new file mode 100644
index 0000000..d1deb5d
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa2.png
new file mode 100644
index 0000000..a849948
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa2.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa.png
new file mode 100644
index 0000000..aa89348
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa2.png
new file mode 100644
index 0000000..802f64f
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa2.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa.png
new file mode 100644
index 0000000..fef1ba3
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa2.png
new file mode 100644
index 0000000..1489f65
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa2.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/kradio_alsa.png
new file mode 100644
index 0000000..11b3ce4
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/kradio_alsa.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/icons/kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/kradio_alsa2.png
new file mode 100644
index 0000000..82d97c0
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/icons/kradio_alsa2.png
Binary files differ
diff --git a/kradio3/plugins/alsa-sound/po/Makefile.am b/kradio3/plugins/alsa-sound/po/Makefile.am
new file mode 100644
index 0000000..9de3420
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/po/Makefile.am
@@ -0,0 +1,3 @@
+
+PACKAGE = kradio-alsa-sound
+POFILES = AUTO
diff --git a/kradio3/plugins/alsa-sound/po/de.po b/kradio3/plugins/alsa-sound/po/de.po
new file mode 100644
index 0000000..9c47ebc
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/po/de.po
@@ -0,0 +1,289 @@
+# translation of de.po to
+# translation of kradio-alsa-sound.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:41+0100\n"
+"PO-Revision-Date: 2006-11-12 18:23+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file alsa-mixer-element-ui.ui line 16
+#: rc.cpp:3 rc.cpp:70 alsa-mixer-element-ui.cpp:104
+#, no-c-format
+msgid "Form1"
+msgstr "Form1"
+
+#. i18n: file alsa-mixer-element-ui.ui line 210
+#: rc.cpp:6 rc.cpp:73 alsa-mixer-element-ui.cpp:105
+#, no-c-format
+msgid "O&n"
+msgstr "A&n"
+
+#. i18n: file alsa-mixer-element-ui.ui line 213
+#: rc.cpp:9 rc.cpp:76 alsa-mixer-element-ui.cpp:106
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#. i18n: file alsa-mixer-element-ui.ui line 221
+#: rc.cpp:12 rc.cpp:79 alsa-mixer-element-ui.cpp:107
+#, no-c-format
+msgid "&Use"
+msgstr "&Verwenden"
+
+#. i18n: file alsa-mixer-element-ui.ui line 224
+#: rc.cpp:15 rc.cpp:82 alsa-mixer-element-ui.cpp:108
+#, no-c-format
+msgid "Alt+U"
+msgstr "Alt+U"
+
+#. i18n: file alsa-mixer-element-ui.ui line 256
+#: rc.cpp:18 rc.cpp:85 alsa-mixer-element-ui.cpp:109
+#, no-c-format
+msgid "MixerName"
+msgstr "MixerName"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 16
+#: rc.cpp:21 rc.cpp:88 alsa-sound-configuration-ui.cpp:152
+#, no-c-format
+msgid "AlsaSoundConfigurationUI"
+msgstr "AlsaSoundConfigurationUI"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 34
+#: rc.cpp:24 rc.cpp:91 alsa-sound-configuration-ui.cpp:161
+#, no-c-format
+msgid "Devices"
+msgstr "Geräte"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 73
+#: rc.cpp:27 rc.cpp:94 alsa-sound-configuration-ui.cpp:153
+#, no-c-format
+msgid "PCM Capture Card"
+msgstr "Soundkarte für die Aufnahme"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 94
+#: rc.cpp:30 rc.cpp:97 alsa-sound-configuration-ui.cpp:154
+#, no-c-format
+msgid "Hardware Buffer Size"
+msgstr "Hardware-Puffergröße"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 123
+#. i18n: file alsa-sound-configuration-ui.ui line 145
+#. i18n: file alsa-sound-configuration-ui.ui line 123
+#. i18n: file alsa-sound-configuration-ui.ui line 145
+#: rc.cpp:33 rc.cpp:36 rc.cpp:100 rc.cpp:103
+#: alsa-sound-configuration-ui.cpp:155 alsa-sound-configuration-ui.cpp:156
+#, no-c-format
+msgid " kB"
+msgstr " kB"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 172
+#: rc.cpp:39 rc.cpp:106 alsa-sound-configuration-ui.cpp:157
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Puffergröße"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 193
+#: rc.cpp:42 rc.cpp:109 alsa-sound-configuration-ui.cpp:158
+#, no-c-format
+msgid "PCM Playback Device"
+msgstr "Gerät für die Wiedergabe"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 201
+#: rc.cpp:45 rc.cpp:112 alsa-sound-configuration-ui.cpp:159
+#, no-c-format
+msgid "PCM Capture Device"
+msgstr "Gerät für die Aufnahme"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 209
+#: rc.cpp:48 rc.cpp:115 alsa-sound-configuration-ui.cpp:160
+#, no-c-format
+msgid "PCM Playback Card"
+msgstr "Soundkarte für die Wiedergabe"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 221
+#: rc.cpp:51 rc.cpp:118 alsa-sound-configuration-ui.cpp:166
+#, no-c-format
+msgid "E&xtended Options"
+msgstr "Erweiterte Optionen"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 235
+#: rc.cpp:54 rc.cpp:121 alsa-sound-configuration-ui.cpp:162
+#, no-c-format
+msgid "Disable Pla&yback"
+msgstr "Wiedergabe abschalten"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 238
+#: rc.cpp:57 rc.cpp:124 alsa-sound-configuration-ui.cpp:163
+#, no-c-format
+msgid "Alt+Y"
+msgstr "Alt+Y"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 246
+#: rc.cpp:60 rc.cpp:127 alsa-sound-configuration-ui.cpp:164
+#, no-c-format
+msgid "Disa&ble Capture"
+msgstr "Aufnahme abschalten"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 249
+#: rc.cpp:63 rc.cpp:130 alsa-sound-configuration-ui.cpp:165
+#, no-c-format
+msgid "Alt+B"
+msgstr "Alt+B"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 276
+#: rc.cpp:66 rc.cpp:133 alsa-sound-configuration-ui.cpp:168
+#, no-c-format
+msgid "Capture Mixer Settings"
+msgstr "Mixereinstellungen für die Aufnahme"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: alsa-sound-configuration.cpp:258
+msgid "context-card-plus-device-number"
+msgstr "%1 Gerät %2"
+
+#: alsa-sound.cpp:40
+msgid "Advanced Linux Sound Architecture (ALSA) Support"
+msgstr "Unterstützung für die \"Advanced Linux Sound Architecture\" (ALSA)"
+
+#: alsa-sound.cpp:48
+msgid "KRadio ALSA Sound Plugin"
+msgstr "KRadio ALSA Sound Plugin"
+
+#: alsa-sound.cpp:196
+msgid "ALSA Sound"
+msgstr "ALSA Sound"
+
+#: alsa-sound.cpp:197
+msgid "ALSA Sound Device Options"
+msgstr "Optionen für die ALSA-Sound-Geräte"
+
+#: alsa-sound.cpp:553
+msgid "ALSA Plugin: cannot write data for device plughw:%1,%2"
+msgstr "ALSA Plugin: Das schreiben auf das Gerät plughw:%1,%2 schlug fehl"
+
+#: alsa-sound.cpp:558
+msgid "ALSA Plugin: buffer underrun for device plughw:%1,%2"
+msgstr "ALSA Plugin: Pufferunterlauf im Gerät plughw:%1,%2"
+
+#: alsa-sound.cpp:611
+msgid "ALSA Plugin: cannot read data from device plughw:%1,%2"
+msgstr "ALSA Plugin: Das Lesen vom Gerät plughw:%1,%2 schlug fehl"
+
+#: alsa-sound.cpp:616
+msgid ""
+"ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer=%"
+"4)"
+msgstr ""
+"ALSA Plugin: Pufferüberlauf im Gerät plughw:%1,%2 (Puffergröße=%3, buffer=%4)"
+
+#: alsa-sound.cpp:626
+msgid "internal stream, not stored (%1)"
+msgstr "interner, nicht aufgezeichneter Datenstrom (%1)"
+
+#: alsa-sound.cpp:736
+msgid "ALSA Plugin: Error opening PCM device %1"
+msgstr "ALSA Plugin: Fehler beim Öffnen des Gerätes %1"
+
+#: alsa-sound.cpp:741
+msgid "ALSA Plugin: Can not configure PCM device %1"
+msgstr "ALSA Plugin: Das Konfigurieren des Gerätes %1 schlug fehl"
+
+#: alsa-sound.cpp:748
+msgid "ALSA Plugin: Error setting access for %1"
+msgstr "ALSA Plugin: Fehler beim Konfigurieren des Zugriffsmodus auf Gerät %1"
+
+#: alsa-sound.cpp:758
+msgid "ALSA Plugin: Error setting sample format for %1"
+msgstr "ALSA Plugin: Fehler beim Einstellen des Abtastformats für Gerät %1"
+
+#: alsa-sound.cpp:764
+msgid "ALSA Plugin: Error setting channels for %1"
+msgstr "ALSA Plugin: Fehler beim Einstellen der Kanäle für Gerät %1"
+
+#: alsa-sound.cpp:771
+msgid "ALSA Plugin: Error setting rate for %1"
+msgstr "ALSA Plugin: Fehler beim Einstellen der Abtastrate für Gerät %1"
+
+#: alsa-sound.cpp:775
+msgid ""
+"ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 "
+"Hz instead"
+msgstr ""
+"ALSA Plugin: Die Abtastrate von %1 Hz wird von Ihrer Soundkarte %2 nicht "
+"unterstützt. Es werden stattdessen %3 Hz verwendet"
+
+#: alsa-sound.cpp:781
+msgid "ALSA Plugin: Error setting period size for %1"
+msgstr ""
+"ALSA Plugin: Fehler beim Einstellen der Puffer-Periodengröße für Gerät %1"
+
+#: alsa-sound.cpp:817
+msgid "ALSA Plugin: Error setting HW params"
+msgstr "ALSA Plugin: Fehler beim Einstellen der Hardwareparameter"
+
+#: alsa-sound.cpp:822
+msgid "ALSA Plugin: Error getting period size for %1"
+msgstr "ALSA Plugin: Fehler beim Lesen der Puffer-Periodengröße von Gerät %1"
+
+#: alsa-sound.cpp:920
+msgid "ALSA Plugin: Error opening mixer"
+msgstr "ALSA Plugin: Fehler beim Öffnen des Mixers"
+
+#: alsa-sound.cpp:927
+msgid "ALSA Plugin: ERROR: snd_mixer_attach for card %1"
+msgstr "ALSA Plugin: Fehler in Funktion snd_mixer_attach bei Soundkarte %1"
+
+#: alsa-sound.cpp:934
+msgid "ALSA Plugin: Error: snd_mixer_selem_register for card %1"
+msgstr ""
+"ALSA Plugin: Fehler in Funktion snd_mixer_selem_register bei Soundkarte %1"
+
+#: alsa-sound.cpp:938
+msgid "ALSA Plugin: Error: snd_mixer_load for card %1"
+msgstr "ALSA Plugin: Fehler in Funktion snd_mixer_load bei Soundkarte %1"
+
+#: alsa-sound.cpp:1006
+msgid "context-mixername-number"
+msgstr "%1 - %2"
+
+#: alsa-sound.cpp:1053
+msgid "context-mixerelement-name-number"
+msgstr "%1 - %2"
+
+#: alsa-sound.cpp:1206 alsa-sound.cpp:1236
+msgid "error while reading volume from hwplug:%1,%2"
+msgstr "Fehler beim Lesen der Lautstärke von Gerät hwplug:%1,%2"
+
+#: alsa-sound.cpp:1269 alsa-sound.cpp:1304
+msgid "error while writing volume %1 to hwplug:%2,%3"
+msgstr "Fehler beim Setzen der Lautstärke von Gerät hwplug:%1,%2"
+
+#: alsa-sound.cpp:1327
+msgid "error while setting capture switch %1 for hwplug:%2,%3"
+msgstr ""
+"Fehler beim Einstellen des Aufnahmeauswahlschalters %1 für Gerät hwplug:%2,%3"
+
+#: alsa-sound.cpp:1448
+msgid "ALSA Sound Device %1"
+msgstr "ALSA Soundkarte %1"
diff --git a/kradio3/plugins/alsa-sound/po/ru.po b/kradio3/plugins/alsa-sound/po/ru.po
new file mode 100644
index 0000000..afdd1cc
--- /dev/null
+++ b/kradio3/plugins/alsa-sound/po/ru.po
@@ -0,0 +1,288 @@
+# translation of ru.po to
+# translation of kradio-alsa-sound.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:20+0100\n"
+"PO-Revision-Date: 2006-11-08 12:15+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file alsa-mixer-element-ui.ui line 16
+#: rc.cpp:3 rc.cpp:70 alsa-mixer-element-ui.cpp:104
+#, no-c-format
+msgid "Form1"
+msgstr "Form1"
+
+#. i18n: file alsa-mixer-element-ui.ui line 210
+#: rc.cpp:6 rc.cpp:73 alsa-mixer-element-ui.cpp:105
+#, no-c-format
+msgid "O&n"
+msgstr "&Вкл."
+
+#. i18n: file alsa-mixer-element-ui.ui line 213
+#: rc.cpp:9 rc.cpp:76 alsa-mixer-element-ui.cpp:106
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#. i18n: file alsa-mixer-element-ui.ui line 221
+#: rc.cpp:12 rc.cpp:79 alsa-mixer-element-ui.cpp:107
+#, no-c-format
+msgid "&Use"
+msgstr "&Исп."
+
+#. i18n: file alsa-mixer-element-ui.ui line 224
+#: rc.cpp:15 rc.cpp:82 alsa-mixer-element-ui.cpp:108
+#, no-c-format
+msgid "Alt+U"
+msgstr "Alt+U"
+
+#. i18n: file alsa-mixer-element-ui.ui line 256
+#: rc.cpp:18 rc.cpp:85 alsa-mixer-element-ui.cpp:109
+#, no-c-format
+msgid "MixerName"
+msgstr ""
+
+#. i18n: file alsa-sound-configuration-ui.ui line 16
+#: rc.cpp:21 rc.cpp:88 alsa-sound-configuration-ui.cpp:152
+#, no-c-format
+msgid "AlsaSoundConfigurationUI"
+msgstr "AlsaSoundConfigurationUI"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 34
+#: rc.cpp:24 rc.cpp:91 alsa-sound-configuration-ui.cpp:161
+#, no-c-format
+msgid "Devices"
+msgstr "Устройства"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 73
+#: rc.cpp:27 rc.cpp:94 alsa-sound-configuration-ui.cpp:153
+#, no-c-format
+msgid "PCM Capture Card"
+msgstr "Плата для захвата"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 94
+#: rc.cpp:30 rc.cpp:97 alsa-sound-configuration-ui.cpp:154
+#, no-c-format
+msgid "Hardware Buffer Size"
+msgstr "Аппаратный размер буфера"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 123
+#. i18n: file alsa-sound-configuration-ui.ui line 145
+#. i18n: file alsa-sound-configuration-ui.ui line 123
+#. i18n: file alsa-sound-configuration-ui.ui line 145
+#: rc.cpp:33 rc.cpp:36 rc.cpp:100 rc.cpp:103
+#: alsa-sound-configuration-ui.cpp:155 alsa-sound-configuration-ui.cpp:156
+#, no-c-format
+msgid " kB"
+msgstr " кБ"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 172
+#: rc.cpp:39 rc.cpp:106 alsa-sound-configuration-ui.cpp:157
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Размер буфера"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 193
+#: rc.cpp:42 rc.cpp:109 alsa-sound-configuration-ui.cpp:158
+#, no-c-format
+msgid "PCM Playback Device"
+msgstr "Устройство воспроизведения"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 201
+#: rc.cpp:45 rc.cpp:112 alsa-sound-configuration-ui.cpp:159
+#, no-c-format
+msgid "PCM Capture Device"
+msgstr "Устройство записи"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 209
+#: rc.cpp:48 rc.cpp:115 alsa-sound-configuration-ui.cpp:160
+#, no-c-format
+msgid "PCM Playback Card"
+msgstr "Плата для проигрывания"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 221
+#: rc.cpp:51 rc.cpp:118 alsa-sound-configuration-ui.cpp:166
+#, no-c-format
+msgid "E&xtended Options"
+msgstr "&Дополнительные параметры"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 235
+#: rc.cpp:54 rc.cpp:121 alsa-sound-configuration-ui.cpp:162
+#, no-c-format
+msgid "Disable Pla&yback"
+msgstr "Запретить &воспроизведение"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 238
+#: rc.cpp:57 rc.cpp:124 alsa-sound-configuration-ui.cpp:163
+#, no-c-format
+msgid "Alt+Y"
+msgstr "Alt+Y"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 246
+#: rc.cpp:60 rc.cpp:127 alsa-sound-configuration-ui.cpp:164
+#, no-c-format
+msgid "Disa&ble Capture"
+msgstr "Запретить &запись"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 249
+#: rc.cpp:63 rc.cpp:130 alsa-sound-configuration-ui.cpp:165
+#, no-c-format
+msgid "Alt+B"
+msgstr "Alt+B"
+
+#. i18n: file alsa-sound-configuration-ui.ui line 276
+#: rc.cpp:66 rc.cpp:133 alsa-sound-configuration-ui.cpp:168
+#, no-c-format
+msgid "Capture Mixer Settings"
+msgstr "&Параметры микшера для записи"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: alsa-sound-configuration.cpp:258
+msgid "context-card-plus-device-number"
+msgstr ""
+
+#: alsa-sound.cpp:40
+msgid "Advanced Linux Sound Architecture (ALSA) Support"
+msgstr "Поддержка Расширенной звуковой архитектуры Linux (ALSA)"
+
+#: alsa-sound.cpp:48
+msgid "KRadio ALSA Sound Plugin"
+msgstr "Модуль ALSA для KRadio"
+
+#: alsa-sound.cpp:196
+msgid "ALSA Sound"
+msgstr "ALSA"
+
+#: alsa-sound.cpp:197
+msgid "ALSA Sound Device Options"
+msgstr "Параметры звука для драйвера ALSA"
+
+#: alsa-sound.cpp:553
+msgid "ALSA Plugin: cannot write data for device plughw:%1,%2"
+msgstr "Модуль ALSA: не могу записать данные в устройство plughw:%1,%2"
+
+#: alsa-sound.cpp:558
+msgid "ALSA Plugin: buffer underrun for device plughw:%1,%2"
+msgstr "Модуль ALSA: нехватка данных в буфере устройства plughw:%1,%2"
+
+#: alsa-sound.cpp:611
+msgid "ALSA Plugin: cannot read data from device plughw:%1,%2"
+msgstr "Модуль ALSA: не могу прочесть данные с устройства plughw:%1,%2"
+
+#: alsa-sound.cpp:616
+msgid ""
+"ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer=%"
+"4)"
+msgstr ""
+"Модуль ALSA: переполнение буфера устройства plughw:%1,%2 (размер буфера=%3, "
+"буфер=%4)"
+
+#: alsa-sound.cpp:626
+msgid "internal stream, not stored (%1)"
+msgstr ""
+
+#: alsa-sound.cpp:736
+msgid "ALSA Plugin: Error opening PCM device %1"
+msgstr "Модуль ALSA: Ошибка при открытии устройства PCM: %1"
+
+#: alsa-sound.cpp:741
+msgid "ALSA Plugin: Can not configure PCM device %1"
+msgstr "Модуль ALSA: не могу настроить устройство PCM %1"
+
+#: alsa-sound.cpp:748
+msgid "ALSA Plugin: Error setting access for %1"
+msgstr ""
+
+#: alsa-sound.cpp:758
+msgid "ALSA Plugin: Error setting sample format for %1"
+msgstr "Модуль ALSA: ошибка при установке формата данных для %1"
+
+#: alsa-sound.cpp:764
+msgid "ALSA Plugin: Error setting channels for %1"
+msgstr "Модуль ALSA: ошибка при установке числа каналов для %1"
+
+#: alsa-sound.cpp:771
+msgid "ALSA Plugin: Error setting rate for %1"
+msgstr "Модуль ALSA: ошибка при установке частоты дискретизации для %1"
+
+#: alsa-sound.cpp:775
+msgid ""
+"ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 "
+"Hz instead"
+msgstr ""
+"Модуль ALSA: частота дискретизации %1 Гц не поддерживается Вашим "
+"оборудованием %2. Вместо неё использую %3 Гц."
+
+#: alsa-sound.cpp:781
+msgid "ALSA Plugin: Error setting period size for %1"
+msgstr ""
+
+#: alsa-sound.cpp:817
+msgid "ALSA Plugin: Error setting HW params"
+msgstr "Модуль ALSA: ошибка при установке параметров оборудоания"
+
+#: alsa-sound.cpp:822
+msgid "ALSA Plugin: Error getting period size for %1"
+msgstr ""
+
+#: alsa-sound.cpp:920
+msgid "ALSA Plugin: Error opening mixer"
+msgstr "Модуль ALSA: ошибка при открытии микшера"
+
+#: alsa-sound.cpp:927
+msgid "ALSA Plugin: ERROR: snd_mixer_attach for card %1"
+msgstr "Модуль ALSA: ошибка при вызове функции snd_mixer_attach для платы %1"
+
+#: alsa-sound.cpp:934
+msgid "ALSA Plugin: Error: snd_mixer_selem_register for card %1"
+msgstr ""
+"Модуль ALSA: ошибка при вызове функции snd_mixer_selem_register для платы %1"
+
+#: alsa-sound.cpp:938
+msgid "ALSA Plugin: Error: snd_mixer_load for card %1"
+msgstr "Модуль ALSA: ошибка при вызове функции snd_mixer_load для платы %1"
+
+#: alsa-sound.cpp:1006
+msgid "context-mixername-number"
+msgstr "context-mixername-number"
+
+#: alsa-sound.cpp:1053
+msgid "context-mixerelement-name-number"
+msgstr "context-mixerelement-name-number"
+
+#: alsa-sound.cpp:1206 alsa-sound.cpp:1236
+msgid "error while reading volume from hwplug:%1,%2"
+msgstr "Ошибка считывания громкости устройства hwplug:%1,%2"
+
+#: alsa-sound.cpp:1269 alsa-sound.cpp:1304
+msgid "error while writing volume %1 to hwplug:%2,%3"
+msgstr "Ошибка при записи громкости %1 в устройство hwplug:%2,%3"
+
+#: alsa-sound.cpp:1327
+msgid "error while setting capture switch %1 for hwplug:%2,%3"
+msgstr "Ошибка при установке флажка записи %1 для устройства hwplug:%2,%3"
+
+#: alsa-sound.cpp:1448
+msgid "ALSA Sound Device %1"
+msgstr "Устройство ALSA: %1"
diff --git a/kradio3/plugins/gui-docking-menu/Makefile.am b/kradio3/plugins/gui-docking-menu/Makefile.am
new file mode 100644
index 0000000..be50ef5
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po .
+
+INCLUDES = -I$(top_builddir)/kradio3/src $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libdocking-menu.la
+libdocking_menu_la_SOURCES = docking-configuration.cpp docking.cpp
+libdocking_menu_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = docking-configuration.h docking.h
+
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-docking-menu.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-docking-menu.pot
diff --git a/kradio3/plugins/gui-docking-menu/docking-configuration.cpp b/kradio3/plugins/gui-docking-menu/docking-configuration.cpp
new file mode 100644
index 0000000..3e32c64
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/docking-configuration.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ docking-configuration.cpp - description
+ -------------------
+ begin : Son Aug 3 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 "docking-configuration.h"
+
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qframe.h>
+
+#include <klocale.h>
+
+using namespace std;
+
+DockingConfiguration::DockingConfiguration (RadioDocking *docking, QWidget *parent)
+ : StationSelector(parent),
+ m_docking(docking),
+ m_disableGUIUpdates(false)
+{
+ QHBoxLayout *layout = new QHBoxLayout();
+ QHBoxLayout *layout2 = new QHBoxLayout();
+
+ m_labelClickMode = new QLabel(this);
+ layout->addWidget(m_labelClickMode);
+
+ m_comboClickMode = new QComboBox(this);
+ layout->addWidget(m_comboClickMode);
+
+ QSpacerItem *spacer = new QSpacerItem( 20, 2, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ layout->addItem(spacer);
+
+ QFrame *line = new QFrame(this);
+ line->setFrameShape ( QFrame::HLine );
+ line->setFrameShadow( QFrame::Sunken );
+ layout2->addWidget(line);
+
+ StationSelectorUILayout->expand(2,0);
+ StationSelectorUILayout->addMultiCellLayout(layout2, 2, 2, 0, 2);
+ StationSelectorUILayout->addMultiCellLayout(layout, 3, 3, 0, 2);
+
+ connect(m_comboClickMode, SIGNAL(activated( int )), this, SLOT(slotSetDirty()));
+
+ languageChange();
+ slotCancel();
+}
+
+
+DockingConfiguration::~DockingConfiguration ()
+{
+}
+
+
+void DockingConfiguration::languageChange()
+{
+ StationSelector::languageChange();
+ m_labelClickMode->setText( i18n( "Left Mouse Click on Tray" ) );
+
+ m_comboClickMode->clear();
+ m_comboClickMode->insertItem(i18n("Show/Hide all GUI Elements"));
+ m_comboClickMode->insertItem(i18n("Power On/Off"));
+}
+
+void DockingConfiguration::slotOK()
+{
+ if (m_dirty) {
+ StationSelector::slotOK();
+ bool old = m_disableGUIUpdates;
+ m_disableGUIUpdates = true;
+ if (m_docking)
+ m_docking->setLeftClickAction((LeftClickAction)m_comboClickMode->currentItem());
+ m_disableGUIUpdates = old;
+ m_dirty = false;
+ }
+}
+
+void DockingConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ StationSelector::slotCancel();
+ if (m_docking)
+ m_comboClickMode->setCurrentItem(m_docking->getLeftClickAction());
+ m_dirty = false;
+ }
+}
+
+void DockingConfiguration::slotLeftClickActionChanged(LeftClickAction action)
+{
+ if (!m_disableGUIUpdates) {
+ if (m_docking)
+ m_comboClickMode->setCurrentItem(action);
+ }
+}
+
+void DockingConfiguration::slotSetDirty()
+{
+ m_dirty = true;
+}
+
+
+#include "docking-configuration.moc"
diff --git a/kradio3/plugins/gui-docking-menu/docking-configuration.h b/kradio3/plugins/gui-docking-menu/docking-configuration.h
new file mode 100644
index 0000000..77b17cf
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/docking-configuration.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ docking-configuration.h - description
+ -------------------
+ begin : Son Aug 3 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_DOCKING_CONFIGURATION_H
+#define KRADIO_DOCKING_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/stationselector.h"
+#include "docking.h"
+
+class QComboBox;
+class QLabel;
+
+class DockingConfiguration : public StationSelector
+{
+Q_OBJECT
+public :
+ DockingConfiguration (RadioDocking *docking, QWidget *parent);
+ ~DockingConfiguration ();
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+ void slotLeftClickActionChanged(LeftClickAction action);
+ void languageChange();
+
+protected:
+ RadioDocking *m_docking;
+ QComboBox *m_comboClickMode;
+ QLabel *m_labelClickMode;
+ bool m_disableGUIUpdates;
+};
+
+#endif
diff --git a/kradio3/plugins/gui-docking-menu/docking.cpp b/kradio3/plugins/gui-docking-menu/docking.cpp
new file mode 100644
index 0000000..e39ae32
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/docking.cpp
@@ -0,0 +1,674 @@
+/***************************************************************************
+ docking.cpp - description
+ -------------------
+ begin : Don Mr 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 <qtooltip.h>
+#include <kpopupmenu.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kdialogbase.h>
+#include <kaboutdata.h>
+#include <kconfig.h>
+#include <kwin.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 QString &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();
+ QObject::connect(m_menu, SIGNAL(activated(int)),
+ this, 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 QStringList &sl)
+{
+ if (m_stationIDs != sl) {
+ m_stationIDs = sl;
+ buildContextMenu();
+ notifyStationSelectionChanged(m_stationIDs);
+ }
+ return true;
+}
+
+
+// PluginBase
+
+void RadioDocking::restoreState (KConfig *config)
+{
+ config->setGroup(QString("radiodocking-") + name());
+
+ m_stationIDs.clear();
+ int nStations = config->readNumEntry("nStations", 0);
+ for (int i = 1; i <= nStations; ++i) {
+ QString s = config->readEntry(QString("stationID-") + QString().setNum(i), QString::null);
+ 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) {
+ QString s = config->readEntry(QString("show_hide_cache_id_%1").arg(i), QString::null);
+ bool b = config->readBoolEntry(QString("show_hide_cache_value_%1").arg(i), false);
+ if (!s.isNull()) {
+ m_widgetsShownCache.insert(s,b);
+ }
+ }
+}
+
+
+void RadioDocking::saveState (KConfig *config) const
+{
+ config->setGroup(QString("radiodocking-") + name());
+
+ config->writeEntry("nStations", m_stationIDs.size());
+ int i = 1;
+ QStringList::const_iterator end = m_stationIDs.end();
+ for (QStringList::const_iterator it = m_stationIDs.begin(); it != end; ++it, ++i) {
+ config->writeEntry(QString("stationID-") + QString().setNum(i), *it);
+ }
+ config->writeEntry("left_click_action", (int)m_leftClickAction);
+
+ config->writeEntry("show_hide_cache_entries", m_widgetsShownCache.count());
+ i = 1;
+ for (QMapConstIterator<QString, bool> it = m_widgetsShownCache.begin(); it != m_widgetsShownCache.end(); ++it, ++i) {
+ config->writeEntry(QString("show_hide_cache_id_%1").arg(i), it.key());
+ config->writeEntry(QString("show_hide_cache_value_%1").arg(i), *it);
+ }
+}
+
+
+ConfigPageInfo RadioDocking::createConfigurationPage()
+{
+ DockingConfiguration *conf = new DockingConfiguration(this, NULL);
+ connectI (conf);
+
+ QObject::connect(this, SIGNAL(sigLeftClickActionChanged(LeftClickAction)),
+ conf, 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, SLOT(slotSleepCountdown()));
+ noticeCountdownStarted(queryCountdownEnd());
+
+ m_seekfwID = m_menu->insertItem(SmallIcon("forward"), i18n("Search Next Station"),
+ this, SLOT(slotSeekFwd()));
+ m_seekbwID = m_menu->insertItem(SmallIcon("back"), i18n("Search Previous Station"),
+ this, SLOT(slotSeekBkwd()));
+
+ // recording menu
+ buildRecordingMenu();
+ m_menu->insertItem(i18n("Recording"), m_recordingMenu);
+
+
+ m_powerID = m_menu->insertItem(SmallIcon("kradio_muteoff"), "power-dummy",
+ this, SLOT(slotPower()));
+ m_pauseID = m_menu->insertItem(SmallIcon("kradio_pause"), i18n("Pause Radio"),
+ this, SLOT(slotPause()));
+ noticePowerChanged(queryIsPowerOn());
+
+ m_menu->insertSeparator();
+
+ m_menu->insertItem(SmallIcon("kradio"), i18n("&About"), this, 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, SLOT(quit()) );
+
+
+ noticeStationChanged(queryCurrentStation(), -1);
+
+}
+
+
+void RadioDocking::buildStationList()
+{
+ m_stationMenuIDs.clear();
+
+ const RawStationList &sl = queryStations().all();
+ const RadioStation &crs = queryCurrentStation();
+
+ int k = 0;
+ QStringList::iterator end = m_stationIDs.end();
+ for (QStringList::iterator it = m_stationIDs.begin(); it != end; ++it) {
+ const RadioStation &rs = sl.stationWithID(*it);
+
+ if (rs.isValid()) {
+
+ ++k;
+ QString shortcut = k < 10 ? "&"+QString().setNum(k) : k == 10 ? "1&0" : QString().setNum(k);
+ QString name = rs.longName().replace("&", "&&");
+ QString 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)
+{
+ QDateTime 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 QDateTime &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*/)
+{
+ QString s = i18n("invalid station");
+ if (rs.isValid())
+ s = rs.longName();
+
+ QToolTip::add(this, s);
+ m_menu->changeTitle (m_titleID, i18n("KRadio: %1").arg(s));
+ // FIXME: title does not change in opened popupmenu
+
+ QValueList<int>::iterator iit = m_stationMenuIDs.begin();
+ QValueList<int>::iterator end = m_stationMenuIDs.end();
+ QStringList::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( QMouseEvent *e )
+{
+ KSystemTray::mousePressEvent(e);
+
+ switch ( e->button() ) {
+ case 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 (QMapIterator<WidgetPluginBase*, int> it = m_widgetPluginIDs.begin(); it != m_widgetPluginIDs.end(); ++it) {
+ WidgetPluginBase *p = it.key();
+ if (p) {
+ bool visible = p->isAnywhereVisible();
+ QString name = p->name();
+ logDebug(QString("visibility of %1: %2").arg(name).arg(visible));
+ m_widgetsShownCache.insert(name, visible);
+ p->getWidget()->hide();
+ }
+ }
+ }
+ else {
+ QMap<QString, bool> tmpCache = m_widgetsShownCache;
+ int d = KWin::currentDesktop();
+ for (QMapIterator<WidgetPluginBase*, int> it = m_widgetPluginIDs.begin(); it != m_widgetPluginIDs.end(); ++it) {
+ WidgetPluginBase *p = it.key();
+ QString name = p ? p->name() : QString::null;
+ if (p && tmpCache.contains(name) && tmpCache[name]) {
+ p->showOnOrgDesktop();
+ }
+ }
+ m_widgetsShownCache.clear();
+ KWin::setCurrentDesktop(d);
+ }
+}
+
+void RadioDocking::slotMenuItemActivated(int id)
+{
+ const StationList &sl = queryStations();
+ QValueList<int>::iterator iit = m_stationMenuIDs.begin();
+ QValueList<int>::iterator end = m_stationMenuIDs.end();
+ QStringList::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;
+
+ QString 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()
+{
+ QMap<QString, 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);
+ QObject::connect(m, SIGNAL(activated(int)),
+ this, SLOT(slotRecordingMenu(int)));
+ SoundStreamID currentID = queryCurrentSoundStreamID();
+
+ QMapIterator<QString, SoundStreamID> end = streams.end();
+ for (QMapIterator<QString, SoundStreamID> it = streams.begin(); it != end; ++it) {
+
+ SoundStreamID id = *it;
+ QString 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)) {
+ QString 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(QDragEnterEvent* event)
+{
+ bool a = StationDragObject::canDecode(event);
+ if (a)
+ IErrorLogClient::staticLogDebug("contentsDragEnterEvent accepted");
+ else
+ IErrorLogClient::staticLogDebug("contentsDragEnterEvent rejected");
+ event->accept(a);
+}
+
+void RadioDocking::dropEvent(QDropEvent* event)
+{
+ QStringList list;
+
+ if ( StationDragObject::decode(event, list) ) {
+ QStringList l = getStationSelection();
+ for (QValueListConstIterator<QString> it = list.begin(); it != list.end(); ++it)
+ if (!l.contains(*it))
+ l.append(*it);
+ setStationSelection(l);
+ }
+}
+
+#include "docking.moc"
diff --git a/kradio3/plugins/gui-docking-menu/docking.h b/kradio3/plugins/gui-docking-menu/docking.h
new file mode 100644
index 0000000..d9fbfde
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/docking.h
@@ -0,0 +1,189 @@
+/***************************************************************************
+ docking.h - description
+ -------------------
+ begin : Mon Jan 14 2002
+ copyright : (C) 2001, 2002 by Frank Schwanz, Ernst Martin Witte
+ email : schwanz@fh-brandenburg.de, 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_DOCKING_H
+#define KRADIO_DOCKING_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ksystemtray.h>
+#include <qpixmap.h>
+#include <qptrdict.h>
+
+#include "../../src/include/timecontrol_interfaces.h"
+#include "../../src/include/radio_interfaces.h"
+#include "../../src/include/radiodevicepool_interfaces.h"
+#include "../../src/include/stationselection_interfaces.h"
+#include "../../src/include/plugins.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+enum LeftClickAction { lcaShowHide = 0, lcaPowerOnOff = 1 };
+
+class RadioDocking : public KSystemTray,
+ public PluginBase,
+ public IRadioClient,
+ public ITimeControlClient,
+ public IRadioDevicePoolClient,
+ public IStationSelection,
+ public ISoundStreamClient
+{
+Q_OBJECT
+public:
+ RadioDocking (const QString &name);
+ virtual ~RadioDocking();
+
+ virtual bool connectI (Interface *);
+ virtual bool disconnectI (Interface *);
+
+ virtual QString pluginClassName() const { return "RadioDocking"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+
+ // IStationSelection
+
+RECEIVERS:
+ bool setStationSelection(const QStringList &sl);
+
+ANSWERS:
+ const QStringList & getStationSelection () const { return m_stationIDs; }
+
+
+ // IRadioDevicePoolClient
+
+RECEIVERS:
+ bool noticeActiveDeviceChanged(IRadioDevice *) { return false; }
+ bool noticeDevicesChanged(const QPtrList<IRadioDevice> &) { return false; }
+ bool noticeDeviceDescriptionChanged(const QString &) { return false; }
+
+ // ITimeControlClient
+
+RECEIVERS:
+ bool noticeAlarmsChanged(const AlarmVector &) { return false; }
+ bool noticeAlarm(const Alarm &) { return false; }
+ bool noticeNextAlarmChanged(const Alarm *);
+ bool noticeCountdownStarted(const QDateTime &/*end*/);
+ bool noticeCountdownStopped();
+ bool noticeCountdownZero();
+ bool noticeCountdownSecondsChanged(int n);
+
+
+ // IRadioClient
+
+RECEIVERS:
+ bool noticePowerChanged(bool on);
+ bool noticeStationChanged (const RadioStation &, int idx);
+ bool noticeStationsChanged(const StationList &sl);
+ bool noticePresetFileChanged(const QString &/*f*/) { return false; }
+
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; }
+
+ // ISoundStreamClient
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool startRecordingWithFormat(SoundStreamID /*id*/,
+ const SoundFormat &/*proposed_format*/,
+ SoundFormat &/*real_format*/);
+ bool stopRecording(SoundStreamID /*id*/);
+
+ bool noticeSoundStreamChanged(SoundStreamID id);
+
+
+protected slots:
+
+ void slotSeekFwd();
+ void slotSeekBkwd();
+
+ void slotPower();
+ void slotPause();
+ void slotSleepCountdown();
+ void slotShowAbout();
+
+ void slotMenuItemActivated(int id);
+ void slotRecordingMenu(int i);
+
+protected:
+ void mousePressEvent( QMouseEvent *e );
+
+ void buildContextMenu();
+ void buildRecordingMenu();
+ void buildStationList();
+
+ void noticeWidgetPluginShown(WidgetPluginBase *, bool shown);
+ void noticePluginsChanged(const PluginList &);
+
+ void showEvent(QShowEvent *) {} // do nothing, original implementation adds "Quit" menu item
+
+ void ShowHideWidgetPlugins();
+
+ void dragEnterEvent(QDragEnterEvent* event);
+ void dropEvent(QDropEvent* event);
+
+public:
+
+ LeftClickAction getLeftClickAction() const { return m_leftClickAction; }
+ void setLeftClickAction(LeftClickAction action);
+
+signals:
+ void sigLeftClickActionChanged(LeftClickAction action);
+
+protected:
+
+ KPopupMenu *m_menu;
+ KPopupMenu *m_pluginMenu;
+ KPopupMenu *m_recordingMenu;
+ QStringList m_stationIDs;
+
+ // menu Item IDs
+ int m_titleID;
+ int m_alarmID;
+ int m_recordingID;
+ int m_powerID;
+ int m_pauseID;
+ int m_sleepID;
+ int m_seekfwID;
+ int m_seekbwID;
+ QValueList<int> m_stationMenuIDs;
+
+ QMap<WidgetPluginBase *, int> m_widgetPluginIDs;
+
+ int m_NextRecordingMenuID;
+ QMap<int, SoundStreamID> m_MenuID2StreamID;
+ QMap<SoundStreamID, int> m_StreamID2MenuID;
+
+ LeftClickAction m_leftClickAction;
+
+ QMap<QString, bool> m_widgetsShownCache;
+};
+
+
+#endif
diff --git a/kradio3/plugins/gui-docking-menu/po/Makefile.am b/kradio3/plugins/gui-docking-menu/po/Makefile.am
new file mode 100644
index 0000000..e02511d
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-gui-docking-menu
+POFILES = AUTO
diff --git a/kradio3/plugins/gui-docking-menu/po/de.po b/kradio3/plugins/gui-docking-menu/po/de.po
new file mode 100644
index 0000000..3256a25
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/po/de.po
@@ -0,0 +1,117 @@
+# translation of de.po to
+# translation of kradio-gui-docking-menu.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-10 23:20+0100\n"
+"PO-Revision-Date: 2006-11-06 00:36+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: docking-configuration.cpp:70
+msgid "Left Mouse Click on Tray"
+msgstr "Linker Mausklick auf Kontrolleistensymbol"
+
+#: docking-configuration.cpp:73
+msgid "Show/Hide all GUI Elements"
+msgstr "Alle Fenster anzeigen/verstecken"
+
+#: docking-configuration.cpp:74
+msgid "Power On/Off"
+msgstr "Ein/Ausschalten"
+
+#: docking.cpp:44
+msgid "Tray Menu for KRadio"
+msgstr "Kontrollleistenmenü für KRadio"
+
+#: docking.cpp:50
+msgid "Docking Plugin"
+msgstr "Plugin für die Kontrolleiste"
+
+#: docking.cpp:180
+msgid "Docking Menu"
+msgstr "Kontrolleisten-Menü"
+
+#: docking.cpp:181
+msgid "Docking Menu Configuration"
+msgstr "Konfiguration des Kontrollleisten-Menüs"
+
+#: docking.cpp:228
+msgid "Search Next Station"
+msgstr "Suche nächsten Sender"
+
+#: docking.cpp:230
+msgid "Search Previous Station"
+msgstr "Suche vorherigen Sender"
+
+#: docking.cpp:235
+msgid "Recording"
+msgstr "Aufnahme"
+
+#: docking.cpp:240
+msgid "Pause Radio"
+msgstr "Radiowiedergabe pausieren"
+
+#: docking.cpp:252
+msgid "Show/Hide Plugins"
+msgstr "Plugins anzeigen/verstecken"
+
+#: docking.cpp:354
+msgid "next alarm: %1"
+msgstr "Nächstes Wecken: %1"
+
+#: docking.cpp:356
+msgid "<no alarm pending>"
+msgstr "<Wecker nicht aktiv>"
+
+#: docking.cpp:364
+msgid "Stop Sleep Countdown (running until %1)"
+msgstr "Schlummermodus abbrechen (liefe bis %1)"
+
+#: docking.cpp:366 docking.cpp:373 docking.cpp:380
+msgid "Start Sleep Countdown"
+msgstr "Schlummermodus einschalten"
+
+#: docking.cpp:388
+msgid "Power Off"
+msgstr "Ausschalten"
+
+#: docking.cpp:388
+msgid "Power On"
+msgstr "Einschalten"
+
+#: docking.cpp:402
+msgid "invalid station"
+msgstr "ungültiger Sender"
+
+#: docking.cpp:407
+msgid "KRadio: %1"
+msgstr "KRadio: %1"
+
+#: docking.cpp:543 docking.cpp:616 docking.cpp:636
+msgid "Stop Recording of %1"
+msgstr "Aufnahme %1 abbrechen"
+
+#: docking.cpp:599
+msgid "Start Recording"
+msgstr "Aufnahme starten"
diff --git a/kradio3/plugins/gui-docking-menu/po/ru.po b/kradio3/plugins/gui-docking-menu/po/ru.po
new file mode 100644
index 0000000..183c31d
--- /dev/null
+++ b/kradio3/plugins/gui-docking-menu/po/ru.po
@@ -0,0 +1,117 @@
+# translation of ru.po to
+# translation of kradio-gui-docking-menu.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 02:11+0100\n"
+"PO-Revision-Date: 2006-11-08 12:16+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: docking-configuration.cpp:70
+msgid "Left Mouse Click on Tray"
+msgstr "По щелчку левой кнопкой мыши"
+
+#: docking-configuration.cpp:73
+msgid "Show/Hide all GUI Elements"
+msgstr "Показать/скрыть все окна"
+
+#: docking-configuration.cpp:74
+msgid "Power On/Off"
+msgstr "Включить/выключить"
+
+#: docking.cpp:44
+msgid "Tray Menu for KRadio"
+msgstr "Меню лотка для KRadio"
+
+#: docking.cpp:50
+msgid "Docking Plugin"
+msgstr "Модуль системного лотка"
+
+#: docking.cpp:180
+msgid "Docking Menu"
+msgstr "Меню лотка"
+
+#: docking.cpp:181
+msgid "Docking Menu Configuration"
+msgstr "Конфигурация меню лотка"
+
+#: docking.cpp:228
+msgid "Search Next Station"
+msgstr "Искать следующую станцию"
+
+#: docking.cpp:230
+msgid "Search Previous Station"
+msgstr "Искать предыдущую станцию"
+
+#: docking.cpp:235
+msgid "Recording"
+msgstr "Запись"
+
+#: docking.cpp:240
+msgid "Pause Radio"
+msgstr "Приостановить"
+
+#: docking.cpp:252
+msgid "Show/Hide Plugins"
+msgstr "Показать/скрыть"
+
+#: docking.cpp:354
+msgid "next alarm: %1"
+msgstr "След. действие: %1"
+
+#: docking.cpp:356
+msgid "<no alarm pending>"
+msgstr "<Расписание пусто>"
+
+#: docking.cpp:364
+msgid "Stop Sleep Countdown (running until %1)"
+msgstr "Остановить таймер отключения (установлено на %1)"
+
+#: docking.cpp:366 docking.cpp:373 docking.cpp:380
+msgid "Start Sleep Countdown"
+msgstr "Запустить таймер отключения"
+
+#: docking.cpp:388
+msgid "Power Off"
+msgstr "Выключить"
+
+#: docking.cpp:388
+msgid "Power On"
+msgstr "Включить"
+
+#: docking.cpp:402
+msgid "invalid station"
+msgstr "Неверная станция"
+
+#: docking.cpp:407
+msgid "KRadio: %1"
+msgstr "Радиоприёмник KDE"
+
+#: docking.cpp:543 docking.cpp:616 docking.cpp:636
+msgid "Stop Recording of %1"
+msgstr "Остановить запись %1"
+
+#: docking.cpp:599
+msgid "Start Recording"
+msgstr "Начать запись"
diff --git a/kradio3/plugins/gui-error-log/Makefile.am b/kradio3/plugins/gui-error-log/Makefile.am
new file mode 100644
index 0000000..1ac0e60
--- /dev/null
+++ b/kradio3/plugins/gui-error-log/Makefile.am
@@ -0,0 +1,17 @@
+SUBDIRS = po .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = liberror-log.la
+liberror_log_la_SOURCES = errorlog.cpp
+liberror_log_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = errorlog.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-error-log.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-error-log.pot
diff --git a/kradio3/plugins/gui-error-log/errorlog.cpp b/kradio3/plugins/gui-error-log/errorlog.cpp
new file mode 100644
index 0000000..2eb58ad
--- /dev/null
+++ b/kradio3/plugins/gui-error-log/errorlog.cpp
@@ -0,0 +1,263 @@
+/***************************************************************************
+ errorlog.cpp - description
+ -------------------
+ begin : Sa Sep 13 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 "errorlog.h"
+
+#include <qframe.h>
+#include <qdatetime.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <qtextedit.h>
+#include <kfiledialog.h>
+#include <kurl.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+
+#define PAGE_ID_INFO 0
+#define PAGE_ID_WARN 1
+#define PAGE_ID_ERROR 2
+#define PAGE_ID_DEBUG 3
+
+///////////////////////////////////////////////////////////////////////
+
+PLUGIN_LIBRARY_FUNCTIONS(ErrorLog, "kradio-gui-error-log", i18n("Error Logging Window for KRadio"));
+
+/////////////////////////////////////////////////////////////////////////////
+
+ErrorLog::ErrorLog(const QString &name)
+ : KDialogBase(KDialogBase::IconList,
+ "",
+ KDialogBase::Close|KDialogBase::User1,
+ KDialogBase::Close,
+ NULL,
+ name.ascii(),
+ false,
+ false,
+ KGuiItem(i18n("Save &as"), "filesaveas")
+ ),
+ WidgetPluginBase(name, i18n("Error Logger")),
+ init_done(false)
+{
+ QWidget::setCaption(i18n("KRadio Logger"));
+ QFrame *info = addPage(i18n("Information"), i18n("Information"),
+ KGlobal::instance()->iconLoader()->loadIcon(
+ "messagebox_info", KIcon::NoGroup, KIcon::SizeMedium
+ )
+ );
+
+ QGridLayout *linfo = new QGridLayout(info);
+ linfo->setSpacing( 5 );
+ linfo->setMargin ( 0 );
+ m_teInfos = new QTextEdit(info);
+ linfo->addWidget(m_teInfos, 0, 0);
+ m_teInfos->setReadOnly(true);
+ logInfo(i18n("logging started"));
+
+
+ QFrame *warn = addPage(i18n("Warnings"), i18n("Warnings"),
+ KGlobal::instance()->iconLoader()->loadIcon(
+ "messagebox_warning", KIcon::NoGroup, KIcon::SizeMedium
+ )
+ );
+ QGridLayout *lwarn = new QGridLayout(warn);
+ lwarn->setSpacing( 5 );
+ lwarn->setMargin ( 0 );
+ m_teWarnings = new QTextEdit(warn);
+ lwarn->addWidget(m_teWarnings, 0, 0);
+ m_teWarnings->setReadOnly(true);
+ logWarning(i18n("logging started"));
+
+
+
+ QFrame *err = addPage(i18n("Errors"), i18n("Errors"),
+ KGlobal::instance()->iconLoader()->loadIcon(
+ "messagebox_critical", KIcon::NoGroup, KIcon::SizeMedium
+ )
+ );
+ QGridLayout *lerr = new QGridLayout(err);
+ lerr->setSpacing( 5 );
+ lerr->setMargin ( 0 );
+ m_teErrors = new QTextEdit(err);
+ lerr->addWidget(m_teErrors, 0, 0);
+ m_teErrors->setReadOnly(true);
+ logError(i18n("logging started"));
+
+ QFrame *debug = addPage(i18n("Debugging"), i18n("Debugging"),
+ KGlobal::instance()->iconLoader()->loadIcon(
+ "find", KIcon::NoGroup, KIcon::SizeMedium
+ )
+ );
+
+ QGridLayout *ldebug = new QGridLayout(debug);
+ ldebug->setSpacing( 5 );
+ ldebug->setMargin ( 0 );
+ m_teDebug = new QTextEdit(debug);
+ ldebug->addWidget(m_teDebug, 0, 0);
+ m_teDebug->setReadOnly(true);
+ logDebug(i18n("logging started"));
+
+ init_done = true;
+}
+
+
+ErrorLog::~ErrorLog()
+{
+}
+
+bool ErrorLog::connectI (Interface *i)
+{
+ bool a = IErrorLog::connectI(i);
+ bool b = PluginBase::connectI(i);
+ return a || b;
+}
+
+bool ErrorLog::disconnectI (Interface *i)
+{
+ bool a = IErrorLog::disconnectI(i);
+ bool b = PluginBase::disconnectI(i);
+ return a || b;
+}
+
+void ErrorLog::restoreState (KConfig *config)
+{
+ config->setGroup(QString("errorlog-") + WidgetPluginBase::name());
+ WidgetPluginBase::restoreState(config, false);
+}
+
+
+void ErrorLog::saveState (KConfig *config) const
+{
+ config->setGroup(QString("errorlog-") + WidgetPluginBase::name());
+ WidgetPluginBase::saveState(config);
+}
+
+
+void ErrorLog::show()
+{
+ WidgetPluginBase::pShow();
+ KDialogBase::show();
+}
+
+void ErrorLog::showOnOrgDesktop()
+{
+ WidgetPluginBase::pShowOnOrgDesktop();
+ //KDialogBase::show();
+}
+
+void ErrorLog::hide()
+{
+ logDebug(QString("%1, ErrorLog::hide: all: %2, desktop: %3, visible:%4, anywherevisible:%5, cachevalid: %6").arg(name()).arg(m_saveSticky).arg(m_saveDesktop).arg(isReallyVisible()).arg(isAnywhereVisible()).arg(m_geoCacheValid));
+ WidgetPluginBase::pHide();
+ KDialogBase::hide();
+}
+
+void ErrorLog::showEvent(QShowEvent *e)
+{
+ KDialogBase::showEvent(e);
+ WidgetPluginBase::pShowEvent(e);
+}
+
+void ErrorLog::hideEvent(QHideEvent *e)
+{
+ KDialogBase::hideEvent(e);
+ WidgetPluginBase::pHideEvent(e);
+}
+
+// IErrorLog
+
+bool ErrorLog::logError (const QString &s)
+{
+ m_teErrors->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n");
+ if (init_done) {
+ showPage(PAGE_ID_ERROR);
+ show();
+ }
+ return true;
+}
+
+bool ErrorLog::logWarning(const QString &s)
+{
+ m_teWarnings->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n");
+ return true;
+}
+
+bool ErrorLog::logInfo (const QString &s)
+{
+ m_teInfos->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n");
+ return true;
+}
+
+bool ErrorLog::logDebug (const QString &s)
+{
+ m_teDebug->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n");
+ return true;
+}
+
+// KDialogBase
+
+
+// store Log Data
+void ErrorLog::slotUser1()
+{
+ KFileDialog fd("",
+ ("*.log|" + i18n("Log Files") + "( *.log )").ascii(),
+ this,
+ i18n("Select Log File").ascii(),
+ true);
+ fd.setMode(KFile::File);
+ fd.setOperationMode(KFileDialog::Saving);
+ fd.setCaption (i18n("Save KRadio Logging Data as ..."));
+
+ if (fd.exec() == QDialog::Accepted) {
+ KURL url = fd.selectedURL();
+
+ KTempFile tmpFile;
+ tmpFile.setAutoDelete(true);
+ QFile *outf = tmpFile.file();
+
+ QTextStream outs(outf);
+ outs.setEncoding(QTextStream::UnicodeUTF8);
+
+ switch (activePageIndex()) {
+ case PAGE_ID_INFO: outs << m_teInfos->text(); break;
+ case PAGE_ID_WARN: outs << m_teWarnings->text(); break;
+ case PAGE_ID_ERROR: outs << m_teErrors->text(); break;
+ case PAGE_ID_DEBUG: outs << m_teDebug->text(); break;
+ default: break;
+ }
+
+ if (outf->status() != IO_Ok) {
+ logError("ErrorLogger: " +
+ i18n("error writing to tempfile %1").arg(tmpFile.name()));
+ return;
+ }
+
+ // close hopefully flushes buffers ;)
+ outf->close();
+
+ if (!KIO::NetAccess::upload(tmpFile.name(), url, this)) {
+ logError("ErrorLogger: " +
+ i18n("error uploading preset file %1").arg(url.url()));
+ }
+ }
+ setIconListAllVisible(true);
+}
+
+
+#include "errorlog.moc"
diff --git a/kradio3/plugins/gui-error-log/errorlog.h b/kradio3/plugins/gui-error-log/errorlog.h
new file mode 100644
index 0000000..d558037
--- /dev/null
+++ b/kradio3/plugins/gui-error-log/errorlog.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ errorlog.h - description
+ -------------------
+ begin : Sa Sep 13 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_ERRORLOG_H
+#define KRADIO_ERRORLOG_H
+
+#include <kdialogbase.h>
+
+#include "../../src/include/errorlog-interfaces.h"
+#include "../../src/include/widgetplugins.h"
+
+
+class QTextEdit;
+class ErrorLog : public KDialogBase,
+ public WidgetPluginBase,
+ public IErrorLog
+{
+Q_OBJECT
+public:
+ ErrorLog(const QString &name = QString::null);
+ ~ErrorLog();
+
+ virtual QString pluginClassName() const { return "ErrorLog"; }
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ virtual bool connectI (Interface *);
+ virtual bool disconnectI (Interface *);
+
+// WidgetPluginBase
+
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+public slots:
+ virtual void showOnOrgDesktop();
+ virtual void show();
+ virtual void hide();
+ virtual void toggleShown () { WidgetPluginBase::pToggleShown(); }
+
+protected:
+ QWidget *getWidget() { return this; }
+ const QWidget *getWidget() const { return this; }
+
+ virtual void showEvent(QShowEvent *);
+ virtual void hideEvent(QHideEvent *);
+
+ virtual ConfigPageInfo createConfigurationPage () { return ConfigPageInfo(); }
+ virtual AboutPageInfo createAboutPage () { return AboutPageInfo(); }
+
+// IErrorLog
+
+RECEIVERS:
+ bool logError (const QString &);
+ bool logWarning(const QString &);
+ bool logInfo (const QString &);
+ bool logDebug (const QString &);
+
+// KDialogBase
+
+protected slots:
+
+ void slotUser1();
+
+protected:
+
+ QTextEdit *m_teDebug,
+ *m_teInfos,
+ *m_teWarnings,
+ *m_teErrors;
+
+ bool init_done;
+};
+
+#endif
diff --git a/kradio3/plugins/gui-error-log/po/Makefile.am b/kradio3/plugins/gui-error-log/po/Makefile.am
new file mode 100644
index 0000000..c3b26b7
--- /dev/null
+++ b/kradio3/plugins/gui-error-log/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-gui-error-log
+POFILES = AUTO
diff --git a/kradio3/plugins/gui-error-log/po/de.po b/kradio3/plugins/gui-error-log/po/de.po
new file mode 100644
index 0000000..0f357c7
--- /dev/null
+++ b/kradio3/plugins/gui-error-log/po/de.po
@@ -0,0 +1,69 @@
+# translation of de.po to
+# translation of kradio-gui-error-log.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-10 23:20+0100\n"
+"PO-Revision-Date: 2006-11-06 01:15+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: errorlog.cpp:39
+msgid "Error Logging Window for KRadio"
+msgstr "Fehlerprotokollierungsfenster für KRadio"
+
+#: errorlog.cpp:52
+msgid "Save &as"
+msgstr "Sichern &unter"
+
+#: errorlog.cpp:54
+msgid "Error Logger"
+msgstr "Fehlerprotokoll"
+
+#: errorlog.cpp:57
+msgid "KRadio Logger"
+msgstr "KRadio Fehlerprotokoll"
+
+#: errorlog.cpp:70 errorlog.cpp:84 errorlog.cpp:99 errorlog.cpp:113
+msgid "logging started"
+msgstr "Beginn des Protokollierung"
+
+#: errorlog.cpp:73
+msgid "Warnings"
+msgstr "Warnungen"
+
+#: errorlog.cpp:88
+msgid "Errors"
+msgstr "Fehler"
+
+#: errorlog.cpp:101
+msgid "Debugging"
+msgstr "Debugging"
+
+#: errorlog.cpp:219
+msgid "Log Files"
+msgstr "Protokoll-Dateien"
+
+#: errorlog.cpp:221
+msgid "Select Log File"
+msgstr "Auswahl der Protokolldatei"
+
+#: errorlog.cpp:225
+msgid "Save KRadio Logging Data as ..."
+msgstr "KRadio-Fehlerprotokoll sichern untern ..."
+
+#: errorlog.cpp:247
+msgid "error writing to tempfile %1"
+msgstr "Fehler beim schreiben in die temporäre Datei %1"
+
+#: errorlog.cpp:256
+msgid "error uploading preset file %1"
+msgstr "Fehler beim Upload der Senderdatei %1"
diff --git a/kradio3/plugins/gui-error-log/po/ru.po b/kradio3/plugins/gui-error-log/po/ru.po
new file mode 100644
index 0000000..0bac8e7
--- /dev/null
+++ b/kradio3/plugins/gui-error-log/po/ru.po
@@ -0,0 +1,71 @@
+# translation of ru.po to
+# translation of kradio-gui-error-log.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 02:11+0100\n"
+"PO-Revision-Date: 2006-11-08 12:56+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#: errorlog.cpp:39
+msgid "Error Logging Window for KRadio"
+msgstr "Окно ведения журнала ошибок KRadio"
+
+#: errorlog.cpp:52
+msgid "Save &as"
+msgstr "Сохранить &как"
+
+#: errorlog.cpp:54
+msgid "Error Logger"
+msgstr "Журнал ошибок"
+
+#: errorlog.cpp:57
+msgid "KRadio Logger"
+msgstr "Журнал KRadio"
+
+#: errorlog.cpp:70 errorlog.cpp:84 errorlog.cpp:99 errorlog.cpp:113
+msgid "logging started"
+msgstr "Журналирование включено"
+
+#: errorlog.cpp:73
+msgid "Warnings"
+msgstr "Предупреждения"
+
+#: errorlog.cpp:88
+msgid "Errors"
+msgstr "Ошибки"
+
+#: errorlog.cpp:101
+msgid "Debugging"
+msgstr ""
+"Отладочные\n"
+"сообщения"
+
+#: errorlog.cpp:219
+msgid "Log Files"
+msgstr "Файлы журнала"
+
+#: errorlog.cpp:221
+msgid "Select Log File"
+msgstr "Выберите файлы журнала"
+
+#: errorlog.cpp:225
+msgid "Save KRadio Logging Data as ..."
+msgstr "Сохранить данные журнала KRadio как..."
+
+#: errorlog.cpp:247
+msgid "error writing to tempfile %1"
+msgstr "Ошибка записи во временный файл %1"
+
+#: errorlog.cpp:256
+msgid "error uploading preset file %1"
+msgstr "Ошибка выгрузки файла настроек %1"
diff --git a/kradio3/plugins/gui-quickbar/Makefile.am b/kradio3/plugins/gui-quickbar/Makefile.am
new file mode 100644
index 0000000..09c58ee
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po .
+
+INCLUDES = -I$(top_builddir)/kradio3/src $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libquickbar.la
+libquickbar_la_SOURCES = buttonflowlayout.cpp quickbar.cpp \
+ quickbar-configuration.cpp
+libquickbar_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = buttonflowlayout.h quickbar-configuration.h quickbar.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-quickbar.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-quickbar.pot
diff --git a/kradio3/plugins/gui-quickbar/buttonflowlayout.cpp b/kradio3/plugins/gui-quickbar/buttonflowlayout.cpp
new file mode 100644
index 0000000..40d7da4
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/buttonflowlayout.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+** $Id: buttonflowlayout.cpp 272 2005-05-18 08:12:51Z emw $
+**
+** Implementing your own layout: flow example
+**
+** Copyright (C) 1996 by Trolltech AS. All rights reserved.
+**
+** This file is part of an example program for Qt. This example
+** program may be used, distributed and modified without limitation.
+**
+*****************************************************************************/
+/**
+ Modified 2002 by Klas Kalass (klas.kalass@gmx.de) for kradio
+ */
+
+#include <kdebug.h>
+
+#include "buttonflowlayout.h"
+
+/*********************************************/
+/* Iterator */
+class ButtonFlowLayoutIterator :public QGLayoutIterator
+{
+public:
+ ButtonFlowLayoutIterator( QPtrList<QLayoutItem> *l ) :idx(0), list(l) {}
+ uint count() const;
+ QLayoutItem *current();
+ QLayoutItem *next();
+ QLayoutItem *takeCurrent();
+
+private:
+ int idx;
+ QPtrList<QLayoutItem> *list;
+
+};
+
+uint ButtonFlowLayoutIterator::count() const
+{
+ return list->count();
+}
+
+QLayoutItem *ButtonFlowLayoutIterator::current()
+{
+ return idx < int(count()) ? list->at(idx) : 0;
+}
+
+QLayoutItem *ButtonFlowLayoutIterator::next()
+{
+ idx++; return current();
+}
+
+QLayoutItem *ButtonFlowLayoutIterator::takeCurrent()
+{
+ return idx < int(count()) ? list->take( idx ) : 0;
+}
+
+/**************************************************************/
+
+ButtonFlowLayout::ButtonFlowLayout( QWidget *parent, int margin, int spacing,
+ const char *name )
+ : QLayout( parent, margin, spacing, name ),
+ cached_width(0)
+{
+}
+
+ButtonFlowLayout::ButtonFlowLayout( QLayout* parentLayout, int spacing, const char *name )
+ : QLayout( parentLayout, spacing, name ),
+ cached_width(0)
+{
+}
+
+ButtonFlowLayout::ButtonFlowLayout( int spacing, const char *name )
+ : QLayout( spacing, name ),
+ cached_width(0)
+{
+}
+
+ButtonFlowLayout::~ButtonFlowLayout()
+{
+ deleteAllItems();
+}
+
+
+int ButtonFlowLayout::heightForWidth( int w ) const
+{
+ if ( cached_width != w ) {
+ //Not all C++ compilers support "mutable" yet:
+ ButtonFlowLayout * mthis = (ButtonFlowLayout*)this;
+ int h = mthis->doLayout( QRect(0,0,w,0), TRUE );
+ mthis->cached_hfw = h;
+ mthis->cached_width = w;
+ return h;
+ }
+ return cached_hfw;
+}
+
+void ButtonFlowLayout::addItem( QLayoutItem *item)
+{
+ list.append( item );
+}
+
+bool ButtonFlowLayout::hasHeightForWidth() const
+{
+ return TRUE;
+}
+
+QSize ButtonFlowLayout::sizeHint() const
+{
+ return minimumSize();
+}
+
+QSizePolicy::ExpandData ButtonFlowLayout::expanding() const
+{
+ return QSizePolicy::NoDirection;
+}
+
+QLayoutIterator ButtonFlowLayout::iterator()
+{
+ return QLayoutIterator( new ButtonFlowLayoutIterator( &list ) );
+}
+
+void ButtonFlowLayout::setGeometry( const QRect &r )
+{
+ QLayout::setGeometry( r );
+ doLayout( r );
+}
+
+int ButtonFlowLayout::doLayout( const QRect &r, bool testonly )
+{
+/* kdDebug() << "buttonflowlayout::doLayout ("
+ << r.x() << "," << r.y() << ","
+ << r.width() << "," << r.height() << ", " << testonly << ")\n";
+*/
+ float x = r.x();
+ float y = r.y();
+ int h = 0; //height of this line so far.
+ float buttonWidth = 0;
+ int buttonHeight = 0;
+ int linecount = 0;
+ int totalWidth = r.width();
+ int totalHeight = r.height();
+
+ QPtrListIterator<QLayoutItem> it(list);
+ QLayoutItem *o;
+
+ // get the width of the biggest Button
+
+ it.toFirst();
+ while ( (o=it.current()) != 0 ) {
+ ++it;
+ buttonWidth = QMAX( buttonWidth, o->sizeHint().width() );
+ buttonHeight = QMAX( buttonHeight, o->sizeHint().height() );
+ }
+
+ // calculate the optimal width
+ unsigned int columns = (totalWidth + spacing()) /
+ ((int)buttonWidth + spacing());
+ if (columns > it.count() ) columns = it.count();
+ if (columns == 0) columns = 1; // avoid division by zero
+
+
+ int rows = (it.count() - 1) / columns + 1;
+ float deltaH = (float)(totalHeight - rows * buttonHeight - (rows - 1) * spacing())
+ / (float)(rows + 1) ;
+ if (deltaH < 0) deltaH = 0;
+
+ y += deltaH;
+
+ buttonWidth = (float)(totalWidth - spacing()*(columns-1)) / (float)columns;
+
+/* fprintf (stderr, "cols = %i col-width = %f\n"
+ "rows = %i row-height = %i\n"
+ "w = %i h = %i\n",
+ columns, buttonWidth,
+ rows, buttonHeight,
+ totalWidth, totalHeight
+ );
+*/
+ // calculate the positions and sizes
+ it.toFirst();
+ while ( (o = it.current()) != 0 ) {
+
+// fprintf (stderr, "x = %i y = %i\n", x, (int)y);
+ ++it;
+ int btnRight = (int)rint(x + buttonWidth) - 1,
+ btnLeft = (int)rint(x);
+
+ if ( btnRight > r.right() && h > 0 ) {
+ x = r.x();
+ btnRight = (int)rint(x + buttonWidth) - 1;
+ btnLeft = (int)rint(x);
+
+ y += h + spacing() + deltaH;
+ h = 0;
+ linecount++;
+ }
+ if (!testonly)
+ o->setGeometry( QRect( QPoint( btnLeft, (int)rint(y) ),
+ QSize( btnRight - btnLeft + 1,
+ buttonHeight) )
+ );
+
+ x += buttonWidth + spacing();
+ h = QMAX( h, buttonHeight );
+ }
+
+ int ret = (int)rint(y + h + deltaH) - r.y();
+
+// kdDebug() << "ButtonFlowLayout::doLayout() = " << ret << endl;
+ return ret;
+}
+
+
+QSize ButtonFlowLayout::minimumSize() const
+{
+ return minimumSize(geometry().size());
+}
+
+
+QSize ButtonFlowLayout::minimumSize(const QSize &r) const
+{
+ QSize s(0, 0);
+
+ for (QPtrListIterator<QLayoutItem> it(list); it.current(); ++it) {
+ QLayoutItem *o = it.current();
+ s = s.expandedTo( o->sizeHint()); //minimumSize() );
+ }
+
+ s.setHeight(heightForWidth(r.width()));
+
+ return s;
+}
diff --git a/kradio3/plugins/gui-quickbar/buttonflowlayout.h b/kradio3/plugins/gui-quickbar/buttonflowlayout.h
new file mode 100644
index 0000000..337a850
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/buttonflowlayout.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+** $Id: buttonflowlayout.h 471 2006-11-11 17:04:51Z emw $
+**
+** Definition of simple flow layout for custom layout example
+**
+** Created : 979899
+**
+** Copyright (C) 1997 by Trolltech AS. All rights reserved.
+**
+** This file is part of an example program for Qt. This example
+** program may be used, distributed and modified without limitation.
+**
+*****************************************************************************/
+/**
+ Modified 2002 by Klas Kalass (klas.kalass@gmx.de) for kradio
+ */
+#ifndef BUTTONFLOWLAYOUT_H
+#define BUTTONFLOWLAYOUT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/utils.h"
+
+#include <qlayout.h>
+#include <qptrlist.h>
+
+class ButtonFlowLayout : public QLayout
+{
+public:
+ ButtonFlowLayout( QWidget *parent, int margin = 0, int spacing=-1,
+ const char *name=0 );
+
+ ButtonFlowLayout( QLayout* parentLayout, int spacing=-1, const char *name=0 );
+
+ ButtonFlowLayout( int spacing=-1, const char *name=0 );
+
+ ~ButtonFlowLayout();
+
+ void addItem( QLayoutItem *item);
+ bool hasHeightForWidth() const;
+ int heightForWidth( int ) const;
+ QSize sizeHint() const;
+ QSize minimumSize() const;
+ QSize minimumSize(const QSize &r) const; // minimumSize is dependent from width
+ QLayoutIterator iterator();
+ QSizePolicy::ExpandData expanding() const;
+
+protected:
+ void setGeometry( const QRect& );
+
+private:
+ int doLayout( const QRect&, bool testonly = FALSE );
+ QPtrList<QLayoutItem> list;
+ int cached_width;
+ int cached_hfw;
+};
+
+#endif
diff --git a/kradio3/plugins/gui-quickbar/po/Makefile.am b/kradio3/plugins/gui-quickbar/po/Makefile.am
new file mode 100644
index 0000000..fbee5b4
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-gui-quickbar
+POFILES = AUTO
diff --git a/kradio3/plugins/gui-quickbar/po/de.po b/kradio3/plugins/gui-quickbar/po/de.po
new file mode 100644
index 0000000..9ac8533
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/po/de.po
@@ -0,0 +1,53 @@
+# translation of de.po to
+# translation of kradio-gui-quickbar.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-10 23:20+0100\n"
+"PO-Revision-Date: 2006-11-06 00:32+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte "
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: quickbar.cpp:42
+msgid "Radio Station Quick Selection Toolbar"
+msgstr "Senderkurzwahlfenster"
+
+#: quickbar.cpp:48
+msgid "Quickbar Plugin"
+msgstr "Schnellauswahlfenster"
+
+#: quickbar.cpp:139
+msgid "Quickbar"
+msgstr "Kurzwahlfenster"
+
+#: quickbar.cpp:140
+msgid "Quickbar Configuration"
+msgstr "Konfiguration des Kurzwahlfensters"
+
+#: quickbar.cpp:404
+msgid "contentsDragEnterEvent accepted"
+msgstr "contentsDragEnterEvent angenommen"
+
+#: quickbar.cpp:406
+msgid "contentsDragEnterEvent rejected"
+msgstr "contentsDragEnterEvent abgelehnt"
diff --git a/kradio3/plugins/gui-quickbar/po/ru.po b/kradio3/plugins/gui-quickbar/po/ru.po
new file mode 100644
index 0000000..7742fde
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/po/ru.po
@@ -0,0 +1,55 @@
+# translation of ru.po to
+# translation of kradio-gui-quickbar.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 02:11+0100\n"
+"PO-Revision-Date: 2006-11-08 12:00+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: quickbar.cpp:42
+msgid "Radio Station Quick Selection Toolbar"
+msgstr "Панель быстрого выбора радиостанций"
+
+#: quickbar.cpp:48
+msgid "Quickbar Plugin"
+msgstr "Панель быстрого доступа"
+
+#: quickbar.cpp:139
+msgid "Quickbar"
+msgstr ""
+"Панель\n"
+" радиостанций"
+
+#: quickbar.cpp:140
+msgid "Quickbar Configuration"
+msgstr "Настройка панели быстрого доступа"
+
+#: quickbar.cpp:404
+msgid "contentsDragEnterEvent accepted"
+msgstr "contentsDragEnterEvent accepted"
+
+#: quickbar.cpp:406
+msgid "contentsDragEnterEvent rejected"
+msgstr "contentsDragEnterEvent rejected"
diff --git a/kradio3/plugins/gui-quickbar/quickbar-configuration.cpp b/kradio3/plugins/gui-quickbar/quickbar-configuration.cpp
new file mode 100644
index 0000000..bb8b0f6
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/quickbar-configuration.cpp
@@ -0,0 +1,35 @@
+/***************************************************************************
+ quickbar-configuration.cpp - description
+ -------------------
+ begin : Son Aug 3 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 "quickbar-configuration.h"
+
+using namespace std;
+
+QuickbarConfiguration::QuickbarConfiguration (QWidget *parent)
+ : StationSelector(parent)
+{
+}
+
+
+QuickbarConfiguration::~QuickbarConfiguration ()
+{
+}
+
+
+
+
+#include "quickbar-configuration.moc"
diff --git a/kradio3/plugins/gui-quickbar/quickbar-configuration.h b/kradio3/plugins/gui-quickbar/quickbar-configuration.h
new file mode 100644
index 0000000..e2e1c08
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/quickbar-configuration.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ quickbar-configuration.h - description
+ -------------------
+ begin : Son Aug 3 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_QUICKBAR_CONFIGURATION_H
+#define KRADIO_QUICKBAR_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/stationselector.h"
+
+class QuickbarConfiguration : public StationSelector
+{
+Q_OBJECT
+public :
+ QuickbarConfiguration (QWidget *parent);
+ ~QuickbarConfiguration ();
+
+};
+
+#endif
diff --git a/kradio3/plugins/gui-quickbar/quickbar.cpp b/kradio3/plugins/gui-quickbar/quickbar.cpp
new file mode 100644
index 0000000..628a1bf
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/quickbar.cpp
@@ -0,0 +1,424 @@
+/***************************************************************************
+ quickbar.cpp - description
+ -------------------
+ begin : Mon Feb 11 2002
+ copyright : (C) 2002 by Martin Witte / Frank Schwanz
+ email : witte@kawo1.rwth-aachen.de / schwanz@fh-brandenburg.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 <qtooltip.h>
+#include <qnamespace.h>
+#include <qhbuttongroup.h>
+#include <qvbuttongroup.h>
+
+#include <ktoolbarbutton.h>
+#include <kwin.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kaboutdata.h>
+
+#include "../../src/include/aboutwidget.h"
+#include "../../src/include/station-drag-object.h"
+#include "../../src/include/stationlist.h"
+#include "../../src/include/radiostation.h"
+
+#include "buttonflowlayout.h"
+#include "quickbar-configuration.h"
+#include "quickbar.h"
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS(QuickBar, "kradio-gui-quickbar", i18n("Radio Station Quick Selection Toolbar"));
+
+/////////////////////////////////////////////////////////////////////////////
+
+QuickBar::QuickBar(const QString &name)
+ : QWidget(NULL, name.ascii()),
+ WidgetPluginBase(name, i18n("Quickbar Plugin")),
+ m_layout(NULL),
+ m_buttonGroup(NULL),
+ m_showShortName(true),
+ m_ignoreNoticeActivation(false)
+{
+ autoSetCaption();
+ setAcceptDrops(true);
+}
+
+
+QuickBar::~QuickBar()
+{
+}
+
+
+bool QuickBar::connectI(Interface *i)
+{
+ bool a = IRadioClient::connectI(i);
+ bool b = IStationSelection::connectI(i);
+ bool c = PluginBase::connectI(i);
+
+ return a || b || c;
+}
+
+
+bool QuickBar::disconnectI(Interface *i)
+{
+ bool a = IRadioClient::disconnectI(i);
+ bool b = IStationSelection::disconnectI(i);
+ bool c = PluginBase::disconnectI(i);
+
+ return a || b || c;
+}
+
+
+// IStationSelection
+
+bool QuickBar::setStationSelection(const QStringList &sl)
+{
+ if (m_stationIDs != sl) {
+ m_stationIDs = sl;
+ rebuildGUI();
+ notifyStationSelectionChanged(m_stationIDs);
+ }
+ return true;
+}
+
+// PluginBase methods
+
+
+void QuickBar::restoreState (KConfig *config)
+{
+ config->setGroup(QString("quickBar-") + name());
+
+ WidgetPluginBase::restoreState(config, false);
+
+ int nStations = config->readNumEntry("nStations", 0);
+ m_stationIDs.clear();
+ for (int i = 1; i <= nStations; ++i) {
+ QString s = config->readEntry(QString("stationID-") + QString().setNum(i), QString::null);
+ if (s.length())
+ m_stationIDs += s;
+ }
+
+ rebuildGUI();
+ notifyStationSelectionChanged(m_stationIDs);
+}
+
+
+void QuickBar::saveState (KConfig *config) const
+{
+ config->setGroup(QString("quickBar-") + name());
+
+ WidgetPluginBase::saveState(config);
+
+ config->writeEntry("nStations", m_stationIDs.size());
+ int i = 1;
+ QStringList::const_iterator end = m_stationIDs.end();
+ for (QStringList::const_iterator it = m_stationIDs.begin(); it != end; ++it, ++i) {
+ config->writeEntry(QString("stationID-") + QString().setNum(i), *it);
+ }
+}
+
+
+ConfigPageInfo QuickBar::createConfigurationPage()
+{
+ QuickbarConfiguration *conf = new QuickbarConfiguration(NULL);
+ connectI (conf);
+ return ConfigPageInfo(
+ conf,
+ i18n("Quickbar"),
+ i18n("Quickbar Configuration"),
+ "view_icon"
+ );
+}
+
+
+AboutPageInfo QuickBar::createAboutPage()
+{
+/* KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("Quickback 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("Quickbar"),
+ i18n("Quickbar Plugin"),
+ "view_icon"
+ );*/
+ return AboutPageInfo();
+}
+
+
+// IRadio methods
+
+bool QuickBar::noticePowerChanged(bool /*on*/)
+{
+ activateCurrentButton();
+ autoSetCaption();
+ return true;
+}
+
+
+bool QuickBar::noticeStationChanged (const RadioStation &rs, int /*idx*/)
+{
+ if (!m_ignoreNoticeActivation)
+ activateButton(rs);
+ autoSetCaption();
+ return true;
+}
+
+
+bool QuickBar::noticeStationsChanged(const StationList &/*sl*/)
+{
+ // FIXME
+ // we can remove no longer existent stationIDs,
+ // but it doesn't matter if we don't care.
+ rebuildGUI();
+ return true;
+}
+
+
+// button management methods
+
+void QuickBar::buttonClicked(int id)
+{
+ // ouch, but we are still using QStringList :(
+ if (queryIsPowerOn() && id == getButtonID(queryCurrentStation())) {
+ sendPowerOff();
+ } else {
+
+ int k = 0;
+ QStringList::iterator end = m_stationIDs.end();
+ for (QStringList::iterator it = m_stationIDs.begin(); it != end; ++it, ++k) {
+ if (k == id) {
+ const RawStationList &sl = queryStations().all();
+ const RadioStation &rs = sl.stationWithID(*it);
+ bool old = m_ignoreNoticeActivation;
+ m_ignoreNoticeActivation = true;
+ sendActivateStation(rs);
+ m_ignoreNoticeActivation = old;
+ sendPowerOn();
+ }
+ }
+ }
+ // Problem: if we click a button twice, there will be no
+ // "station changed"-notification. Thus it would be possible to
+ // enable a button even if power is off or the radio does not
+ // accept the radiostation
+ //activateCurrentButton();
+}
+
+
+int QuickBar::getButtonID(const RadioStation &rs) const
+{
+ QString stationID = rs.stationID();
+ int k = 0;
+ QStringList::const_iterator end = m_stationIDs.end();
+ for (QStringList::const_iterator it = m_stationIDs.begin(); it != end; ++it, ++k) {
+ if (*it == stationID)
+ return k;
+ }
+ return -1;
+}
+
+
+void QuickBar::activateCurrentButton()
+{
+ activateButton(queryCurrentStation());
+}
+
+
+void QuickBar::activateButton(const RadioStation &rs)
+{
+ int buttonID = getButtonID(rs);
+ bool pwr = queryIsPowerOn();
+
+ if (pwr && buttonID >= 0) {
+ m_buttonGroup->setButton(buttonID);
+ } else {
+ for (QToolButton *b = m_buttons.first(); b; b = m_buttons.next()) {
+ b->setOn(false);
+ }
+ }
+ autoSetCaption();
+}
+
+
+
+// KDE/Qt gui
+
+
+void QuickBar::rebuildGUI()
+{
+ if (m_layout) delete m_layout;
+ if (m_buttonGroup) delete m_buttonGroup;
+
+ for (QPtrListIterator<QToolButton> it(m_buttons); it.current(); ++it)
+ delete it.current();
+ m_buttons.clear();
+
+ m_layout = new ButtonFlowLayout(this);
+ m_layout->setMargin(1);
+ m_layout->setSpacing(2);
+
+ m_buttonGroup = new QButtonGroup(this);
+ QObject::connect (m_buttonGroup, SIGNAL(clicked(int)), this, SLOT(buttonClicked(int)));
+ // we use buttonGroup to enable automatic toggle/untoggle
+ m_buttonGroup->setExclusive(true);
+ m_buttonGroup->setFrameStyle(QFrame::NoFrame);
+ m_buttonGroup->show();
+
+ int buttonID = 0;
+ const RawStationList &stations = queryStations().all();
+
+ QStringList::iterator end = m_stationIDs.end();
+ for (QStringList::iterator it = m_stationIDs.begin(); it != end; ++it, ++buttonID) {
+
+ const RadioStation &rs = stations.stationWithID(*it);
+ if (! rs.isValid()) continue;
+
+ QToolButton *b = new QToolButton(this);
+ m_buttons.append(b);
+ b->setToggleButton(true);
+ if (rs.iconName().length())
+ b->setIconSet(QPixmap(rs.iconName()));
+ else
+ b->setText(m_showShortName ? rs.shortName() : rs.name());
+
+ b->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
+
+ QToolTip::add(b, rs.longName());
+ if (isVisible()) b->show();
+
+
+ m_buttonGroup->insert(b, buttonID);
+ m_layout->add(b);
+ }
+
+ // activate correct button
+ activateCurrentButton();
+
+ // calculate geometry
+ if (m_layout) {
+ QRect r = geometry();
+ int h = m_layout->heightForWidth( r.width());
+
+ if (h > r.height())
+ setGeometry(r.x(), r.y(), r.width(), h);
+ }
+}
+
+
+
+
+void QuickBar::show()
+{
+// KWin::setType(winId(), NET::Toolbar);
+ WidgetPluginBase::pShow();
+ QWidget::show();
+}
+
+
+void QuickBar::showOnOrgDesktop()
+{
+ WidgetPluginBase::pShowOnOrgDesktop();
+ //QWidget::show();
+}
+
+
+void QuickBar::hide()
+{
+ WidgetPluginBase::pHide();
+ QWidget::hide();
+}
+
+void QuickBar::showEvent(QShowEvent *e)
+{
+ QWidget::showEvent(e);
+ WidgetPluginBase::pShowEvent(e);
+}
+
+void QuickBar::hideEvent(QHideEvent *e)
+{
+ QWidget::hideEvent(e);
+ WidgetPluginBase::pHideEvent(e);
+}
+
+
+void QuickBar::setGeometry (int x, int y, int w, int h)
+{
+ if (m_layout) {
+ QSize marginSize(m_layout->margin()*2, m_layout->margin()*2);
+ setMinimumSize(m_layout->minimumSize(QSize(w, h) - marginSize) + marginSize);
+ }
+ QWidget::setGeometry (x, y, w, h);
+}
+
+
+void QuickBar::setGeometry (const QRect &r)
+{
+ setGeometry (r.x(), r.y(), r.width(), r.height());
+}
+
+
+void QuickBar::resizeEvent (QResizeEvent *e)
+{
+ // minimumSize might change because of the flow layout
+ if (m_layout) {
+ QSize marginSize(m_layout->margin()*2, m_layout->margin()*2);
+ setMinimumSize(m_layout->minimumSize(e->size() - marginSize) + marginSize);
+ }
+
+ QWidget::resizeEvent (e);
+}
+
+
+void QuickBar::autoSetCaption()
+{
+ const RadioStation &rs = queryCurrentStation();
+ setCaption((queryIsPowerOn() && rs.isValid()) ? rs.longName() : QString("KRadio"));
+}
+
+void QuickBar::dragEnterEvent(QDragEnterEvent* event)
+{
+ bool a = StationDragObject::canDecode(event);
+ if (a)
+ IErrorLogClient::staticLogDebug(i18n("contentsDragEnterEvent accepted"));
+ else
+ IErrorLogClient::staticLogDebug(i18n("contentsDragEnterEvent rejected"));
+ event->accept(a);
+}
+
+void QuickBar::dropEvent(QDropEvent* event)
+{
+ QStringList list;
+
+ if ( StationDragObject::decode(event, list) ) {
+ QStringList l = getStationSelection();
+ for (QValueListConstIterator<QString> it = list.begin(); it != list.end(); ++it)
+ if (!l.contains(*it))
+ l.append(*it);
+ setStationSelection(l);
+ }
+}
+
+
+#include "quickbar.moc"
diff --git a/kradio3/plugins/gui-quickbar/quickbar.h b/kradio3/plugins/gui-quickbar/quickbar.h
new file mode 100644
index 0000000..7bf5193
--- /dev/null
+++ b/kradio3/plugins/gui-quickbar/quickbar.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+ quickbar.h - description
+ -------------------
+ begin : Mon Feb 11 2002
+ copyright : (C) 2002 by Martin Witte / Klas Kalass
+ 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_QUICKBAR_H
+#define KRADIO_QUICKBAR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+
+#include "../../src/include/radio_interfaces.h"
+#include "../../src/include/widgetplugins.h"
+#include "../../src/include/stationselection_interfaces.h"
+
+class ButtonFlowLayout;
+class QButtonGroup;
+class KConfig;
+class QToolButton;
+
+/**
+ *@author Martin Witte / Klas Kalass
+ */
+
+class QuickBar : public QWidget,
+ public WidgetPluginBase,
+ public IRadioClient,
+ public IStationSelection
+{
+Q_OBJECT
+public:
+ QuickBar(const QString &name = QString::null);
+ ~QuickBar();
+
+ virtual QString pluginClassName() const { return "QuickBar"; }
+
+ const QString &name() const { return PluginBase::name(); }
+ QString &name() { return PluginBase::name(); }
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ // IStationSelection
+
+RECEIVERS:
+ bool setStationSelection(const QStringList &sl);
+
+ANSWERS:
+ const QStringList & getStationSelection () const { return m_stationIDs; }
+
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // IRadioClient
+
+RECEIVERS:
+ bool noticePowerChanged(bool on);
+ bool noticeStationChanged (const RadioStation &, int idx);
+ bool noticeStationsChanged(const StationList &sl);
+ bool noticePresetFileChanged(const QString &/*f*/) { return false; }
+
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; }
+
+ // button/station Management
+
+
+protected slots:
+
+ void buttonClicked(int id);
+
+protected:
+
+ int getButtonID(const RadioStation &rs) const;
+ void activateCurrentButton();
+ void activateButton(const RadioStation &);
+
+ void autoSetCaption();
+
+
+ void dragEnterEvent(QDragEnterEvent* event);
+ void dropEvent(QDropEvent* event);
+
+ // KDE/QT
+
+public slots:
+
+ void toggleShown() { WidgetPluginBase::pToggleShown(); }
+ void show();
+ void hide();
+ void showOnOrgDesktop();
+ void setGeometry (const QRect &r);
+ void setGeometry (int x, int y, int w, int h);
+
+protected:
+ void rebuildGUI();
+ void showEvent(QShowEvent *);
+ void hideEvent(QHideEvent *);
+ void resizeEvent(QResizeEvent *);
+
+ const QWidget *getWidget() const { return this; }
+ QWidget *getWidget() { return this; }
+
+protected :
+
+ ButtonFlowLayout *m_layout;
+ QButtonGroup *m_buttonGroup;
+
+ QPtrList<QToolButton> m_buttons;
+
+ // config
+ bool m_showShortName;
+ QStringList m_stationIDs;
+
+ bool m_ignoreNoticeActivation;
+};
+#endif
diff --git a/kradio3/plugins/gui-standard-display/Makefile.am b/kradio3/plugins/gui-standard-display/Makefile.am
new file mode 100644
index 0000000..a7e7544
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/Makefile.am
@@ -0,0 +1,22 @@
+SUBDIRS = po .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libstandard-display.la
+libstandard_display_la_SOURCES = displaycfg.cpp displaycfg_interfaces.cpp \
+ radioview-configuration.cpp radioview.cpp \
+ radioview_element.cpp \
+ radioview_frequencyradio.cpp \
+ radioview_frequencyseeker.cpp \
+ radioview_volume.cpp
+libstandard_display_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = displaycfg.h displaycfg_interfaces.h radioview-configuration.h radioview_element.h radioview_frequencyradio.h radioview_frequencyseeker.h radioview.h radioview_volume.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-standard-display.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-standard-display.pot
diff --git a/kradio3/plugins/gui-standard-display/displaycfg.cpp b/kradio3/plugins/gui-standard-display/displaycfg.cpp
new file mode 100644
index 0000000..8e26e72
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/displaycfg.cpp
@@ -0,0 +1,145 @@
+/***************************************************************************
+ displaycfg.cpp - description
+ -------------------
+ begin : Fr Aug 15 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 "displaycfg.h"
+#include <kcolorbutton.h>
+#include <kcolordialog.h>
+#include <kfontdialog.h>
+
+#include <qlayout.h>
+#include <klocale.h>
+#include <qlabel.h>
+#include <qbuttongroup.h>
+
+DisplayConfiguration::DisplayConfiguration(QWidget *parent)
+ : QWidget (parent),
+ m_dirty(true),
+ m_ignore_gui_updates(false)
+{
+ QGroupBox *bg = new QGroupBox(i18n("Display Colors"), this);
+ bg->setColumnLayout(0, Qt::Vertical );
+ bg->layout()->setSpacing( 8 );
+ bg->layout()->setMargin( 12 );
+ QGridLayout *gl = new QGridLayout (bg->layout());
+
+ m_btnActive = new KColorButton(queryDisplayActiveColor(), bg);
+ m_btnInactive = new KColorButton(queryDisplayInactiveColor(), bg);
+ m_btnBkgnd = new KColorButton(queryDisplayBkgndColor(), bg);
+
+ connect(m_btnActive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty()));
+ connect(m_btnInactive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty()));
+ connect(m_btnBkgnd, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty()));
+
+ QLabel *l1 = new QLabel(i18n("Active Text"), bg);
+ QLabel *l2 = new QLabel(i18n("Inactive Text"), bg);
+ QLabel *l3 = new QLabel(i18n("Background Color"), bg);
+
+ l1->setAlignment(QLabel::AlignCenter);
+ l2->setAlignment(QLabel::AlignCenter);
+ l3->setAlignment(QLabel::AlignCenter);
+
+ l1->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ l2->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ l3->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ m_btnActive ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ m_btnInactive->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ m_btnBkgnd ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ m_btnActive ->setMinimumSize(QSize(40, 40));
+ m_btnInactive->setMinimumSize(QSize(40, 40));
+ m_btnBkgnd ->setMinimumSize(QSize(40, 40));
+
+ gl->addWidget (l1, 0, 0, Qt::AlignCenter);
+ gl->addWidget (l2, 0, 1, Qt::AlignCenter);
+ gl->addWidget (l3, 0, 2, Qt::AlignCenter);
+ gl->addWidget (m_btnActive, 1, 0);
+ gl->addWidget (m_btnInactive, 1, 1);
+ gl->addWidget (m_btnBkgnd, 1, 2);
+
+ m_fontChooser = new KFontChooser(this, NULL, false, QStringList(), true, 4);
+ m_fontChooser->setFont(queryDisplayFont());
+ m_fontChooser->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ QVBoxLayout *l = new QVBoxLayout(this, 10);
+ l->addWidget(bg);
+ l->addWidget(m_fontChooser);
+
+ connect(m_btnActive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty()));
+ connect(m_btnInactive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty()));
+ connect(m_btnBkgnd, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty()));
+ connect(m_fontChooser, SIGNAL(fontSelected(const QFont &)), this, SLOT(slotSetDirty()));
+
+}
+
+
+DisplayConfiguration::~DisplayConfiguration()
+{
+}
+
+
+bool DisplayConfiguration::noticeDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd)
+{
+ m_ignore_gui_updates = true;
+ m_btnActive->setColor(activeColor);
+ m_btnInactive->setColor(inactiveColor);
+ m_btnBkgnd->setColor(bkgnd);
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+
+bool DisplayConfiguration::noticeDisplayFontChanged(const QFont &f)
+{
+ m_ignore_gui_updates = true;
+ m_fontChooser->setFont(f);
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+
+void DisplayConfiguration::slotOK()
+{
+ if (m_dirty) {
+ sendDisplayColors(m_btnActive->color(), m_btnInactive->color(), m_btnBkgnd->color());
+ sendDisplayFont(m_fontChooser->font());
+ m_dirty = false;
+ }
+}
+
+void DisplayConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ m_ignore_gui_updates = true;
+ m_btnActive ->setColor(queryDisplayActiveColor());
+ m_btnInactive->setColor(queryDisplayInactiveColor());
+ m_btnBkgnd ->setColor(queryDisplayBkgndColor());
+ m_fontChooser->setFont(queryDisplayFont());
+ m_dirty = false;
+ m_ignore_gui_updates = false;
+ }
+}
+
+void DisplayConfiguration::slotSetDirty()
+{
+ if (!m_dirty && !m_ignore_gui_updates) {
+ m_dirty = true;
+ emit sigDirty();
+ }
+}
+
+
+#include "displaycfg.moc"
diff --git a/kradio3/plugins/gui-standard-display/displaycfg.h b/kradio3/plugins/gui-standard-display/displaycfg.h
new file mode 100644
index 0000000..fcd6079
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/displaycfg.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ displaycfg.h - description
+ -------------------
+ begin : Fr Aug 15 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_DISPLAYCFG_H
+#define KRADIO_DISPLAYCFG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "displaycfg_interfaces.h"
+#include <qwidget.h>
+
+class KColorButton;
+class KFontChooser;
+
+class DisplayConfiguration : public QWidget,
+ public IDisplayCfgClient
+{
+Q_OBJECT
+public:
+ DisplayConfiguration(QWidget *parent);
+ ~DisplayConfiguration();
+
+// Interface
+
+ bool connectI (Interface *i) { return IDisplayCfgClient::connectI(i); }
+ bool disconnectI (Interface *i) { return IDisplayCfgClient::disconnectI(i); }
+
+// IDisplayCfgClient
+
+RECEIVERS:
+ bool noticeDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd);
+ bool noticeDisplayFontChanged(const QFont &f);
+
+
+public slots:
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+signals:
+
+ void sigDirty();
+
+protected:
+ KColorButton *m_btnActive;
+ KColorButton *m_btnInactive;
+ KColorButton *m_btnBkgnd;
+ KFontChooser *m_fontChooser;
+
+ bool m_dirty;
+ bool m_ignore_gui_updates;
+};
+
+
+#endif
diff --git a/kradio3/plugins/gui-standard-display/displaycfg_interfaces.cpp b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.cpp
new file mode 100644
index 0000000..a7bbf01
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+ displaycfg_interfaces.cpp - description
+ -------------------
+ begin : Fr Aug 15 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 "displaycfg_interfaces.h"
+
+// IDisplayCfg
+
+IF_IMPL_SENDER ( IDisplayCfg::notifyDisplayColorsChanged(const QColor &a, const QColor &b, const QColor &c),
+ noticeDisplayColorsChanged(a,b, c) )
+
+IF_IMPL_SENDER ( IDisplayCfg::notifyDisplayFontChanged(const QFont &f),
+ noticeDisplayFontChanged(f) )
+
+// IDisplayCfgClient
+
+IF_IMPL_SENDER ( IDisplayCfgClient::sendDisplayColors(const QColor &a, const QColor &b, const QColor &c),
+ setDisplayColors(a,b, c) )
+
+IF_IMPL_SENDER ( IDisplayCfgClient::sendDisplayFont(const QFont &f),
+ setDisplayFont(f) )
+
+const QColor default_display_active_color = QColor(20, 244, 20);
+IF_IMPL_QUERY ( const QColor &IDisplayCfgClient::queryDisplayActiveColor(),
+ getDisplayActiveColor(),
+ default_display_active_color )
+
+const QColor default_display_inactive_color = QColor(10, 117, 10).light(75);
+IF_IMPL_QUERY ( const QColor &IDisplayCfgClient::queryDisplayInactiveColor(),
+ getDisplayInactiveColor(),
+ default_display_inactive_color )
+
+const QColor default_display_bkgnd_color = QColor(10, 117, 10);
+IF_IMPL_QUERY ( const QColor &IDisplayCfgClient::queryDisplayBkgndColor(),
+ getDisplayBkgndColor(),
+ default_display_bkgnd_color )
+
+const QFont default_display_font = QFont("Helvetica");
+IF_IMPL_QUERY ( const QFont &IDisplayCfgClient::queryDisplayFont(),
+ getDisplayFont(),
+ default_display_font )
+
+
+void IDisplayCfgClient::noticeConnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ noticeDisplayColorsChanged(queryDisplayActiveColor(), queryDisplayInactiveColor(), queryDisplayBkgndColor());
+ noticeDisplayFontChanged(queryDisplayFont());
+}
+
+
+void IDisplayCfgClient::noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ noticeDisplayColorsChanged(queryDisplayActiveColor(), queryDisplayInactiveColor(), queryDisplayBkgndColor());
+ noticeDisplayFontChanged(queryDisplayFont());
+}
+
diff --git a/kradio3/plugins/gui-standard-display/displaycfg_interfaces.h b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.h
new file mode 100644
index 0000000..ac2ef5d
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ displaycfg_interfaces.h - description
+ -------------------
+ begin : Fr Aug 15 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_DISPLAYCFG_INTERFACES_H
+#define KRADIO_DISPLAYCFG_INTERFACES_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/interfaces.h"
+
+#include <qfont.h>
+#include <qcolor.h>
+
+///////////////////////////////////////////////////////////////////////
+
+
+INTERFACE(IDisplayCfg, IDisplayCfgClient)
+{
+public :
+ IF_CON_DESTRUCTOR(IDisplayCfg, -1)
+
+RECEIVERS:
+ IF_RECEIVER( setDisplayColors(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) )
+ IF_RECEIVER( setDisplayFont (const QFont &f) )
+
+SENDERS:
+ IF_SENDER ( notifyDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) )
+ IF_SENDER ( notifyDisplayFontChanged(const QFont &f) )
+
+ANSWERS:
+ IF_ANSWER ( const QColor &getDisplayActiveColor() const )
+ IF_ANSWER ( const QColor &getDisplayInactiveColor() const )
+ IF_ANSWER ( const QColor &getDisplayBkgndColor() const )
+ IF_ANSWER ( const QFont &getDisplayFont() const )
+
+};
+
+
+INTERFACE(IDisplayCfgClient, IDisplayCfg)
+{
+friend class IDisplayCfg;
+
+public :
+ IF_CON_DESTRUCTOR(IDisplayCfgClient, 1)
+
+SENDERS:
+ IF_SENDER ( sendDisplayColors(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) )
+ IF_SENDER ( sendDisplayFont (const QFont &f) )
+
+RECEIVERS:
+ IF_RECEIVER( noticeDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) )
+ IF_RECEIVER( noticeDisplayFontChanged(const QFont &f) )
+
+QUERIES:
+ IF_QUERY ( const QColor &queryDisplayActiveColor() )
+ IF_QUERY ( const QColor &queryDisplayInactiveColor() )
+ IF_QUERY ( const QColor &queryDisplayBkgndColor() )
+ IF_QUERY ( const QFont &queryDisplayFont() )
+
+RECEIVERS:
+ virtual void noticeConnectedI (cmplInterface *, bool pointer_valid);
+ virtual void noticeDisconnectedI (cmplInterface *, bool pointer_valid);
+};
+
+
+#endif
diff --git a/kradio3/plugins/gui-standard-display/po/Makefile.am b/kradio3/plugins/gui-standard-display/po/Makefile.am
new file mode 100644
index 0000000..956ae72
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-gui-standard-display
+POFILES = AUTO
diff --git a/kradio3/plugins/gui-standard-display/po/de.po b/kradio3/plugins/gui-standard-display/po/de.po
new file mode 100644
index 0000000..5013f29
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/po/de.po
@@ -0,0 +1,212 @@
+# translation of kradio-gui-standard-display.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: kradio-gui-standard-display\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-06 01:24+0100\n"
+"PO-Revision-Date: 2006-11-06 01:23+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file radioview_seekinterface.ui line 17
+#: rc.cpp:3 rc.cpp:25
+#, no-c-format
+msgid "RadioView_SeekInterface"
+msgstr "RadioView_SeekInterface"
+
+#. i18n: file radioview_seekinterface.ui line 45
+#: rc.cpp:7 rc.cpp:29
+#, no-c-format
+msgid "search previous station"
+msgstr "Suche vorherigen Sender"
+
+#. i18n: file radioview_seekinterface.ui line 73
+#: rc.cpp:11 rc.cpp:33
+#, no-c-format
+msgid "decrease freq. by 0.05 MHz"
+msgstr "Frequenz um 0.05 MHz verringern"
+
+#. i18n: file radioview_seekinterface.ui line 108
+#: rc.cpp:14 rc.cpp:36
+#, no-c-format
+msgid "Frequency control"
+msgstr "Frequenz verändern"
+
+#. i18n: file radioview_seekinterface.ui line 129
+#: rc.cpp:18 rc.cpp:40
+#, no-c-format
+msgid "increase freq. by 0.05 MHz"
+msgstr "Frequenz um 0.05 MHz erhöhen"
+
+#. i18n: file radioview_seekinterface.ui line 146
+#: rc.cpp:22 rc.cpp:44
+#, no-c-format
+msgid "search next station"
+msgstr "Suche nächsten Sender"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: displaycfg.cpp:33
+msgid "Display Colors"
+msgstr "Farben für die Radioanzeige"
+
+#: displaycfg.cpp:47
+msgid "Active Text"
+msgstr "Aktiver Text"
+
+#: displaycfg.cpp:48
+msgid "Inactive Text"
+msgstr "Inaktiver Text"
+
+#: displaycfg.cpp:49
+msgid "Background Color"
+msgstr "Hintergrundfarbe"
+
+#: radioview.cpp:55
+msgid "Standard Display for KRadio"
+msgstr "Standardanzeige für KRadio"
+
+#: radioview.cpp:72
+msgid "Radio Display"
+msgstr "Radio-Anzeige"
+
+#: radioview.cpp:127
+msgid "Pause KRadio"
+msgstr "KRadio pausieren"
+
+#: radioview.cpp:133
+msgid "Start Recording"
+msgstr "Aufnahme starten"
+
+#: radioview.cpp:141
+msgid "5 min"
+msgstr "5 min"
+
+#: radioview.cpp:142
+msgid "10 min"
+msgstr "10 min"
+
+#: radioview.cpp:143
+msgid "15 min"
+msgstr "15 min"
+
+#: radioview.cpp:144
+msgid "30 min"
+msgstr "30 min"
+
+#: radioview.cpp:145
+msgid "60 min"
+msgstr "60 min"
+
+#: radioview.cpp:189
+msgid "Configure KRadio"
+msgstr "KRadio Einrichten"
+
+#: radioview.cpp:190
+msgid "Power On/Off"
+msgstr "Ein/Ausschalten"
+
+#: radioview.cpp:191
+msgid "Quit KRadio Application"
+msgstr "KRadio beenden"
+
+#: radioview.cpp:192
+msgid "Start/Stop Recording"
+msgstr "Aufnahme starten/beenden"
+
+#: radioview.cpp:193
+msgid "Start/Stop Sleep Countdown"
+msgstr "Schlummermodus ein/ausschalten"
+
+#: radioview.cpp:194
+msgid "Show/Hide Plugins"
+msgstr "Plugins anzeigen/verstecken"
+
+#: radioview.cpp:195
+msgid "Select a Radio Station"
+msgstr "Sender auswählen"
+
+#: radioview.cpp:332
+msgid "no preset defined"
+msgstr "kein voreingestellter Sender gefunden"
+
+#: radioview.cpp:442 radioview.cpp:480
+msgid "Stop Recording of %1"
+msgstr "Aufnahme von %1 beenden"
+
+#: radioview.cpp:553
+msgid "Display"
+msgstr "Anzeige"
+
+#: radioview.cpp:554
+msgid "Display Configuration"
+msgstr "Konfiguration der Radio-Anzeige"
+
+#: radioview.cpp:590
+msgid "set Toolbar-Flag for Display"
+msgstr "Werkzeugleisten-Flag für das Displayfenster"
+
+#: radioview.cpp:593
+msgid "Common"
+msgstr "Allgemein"
+
+#: radioview_frequencyradio.cpp:99 radioview_frequencyradio.cpp:100
+msgid "Frequency Display"
+msgstr "Frequenzanzeige"
+
+#: radioview_frequencyradio.cpp:388 radioview_frequencyradio.cpp:389
+msgid "AM"
+msgstr "MW"
+
+#: radioview_frequencyradio.cpp:394 radioview_frequencyradio.cpp:395
+msgid "FM"
+msgstr "UKW"
+
+#: radioview_frequencyradio.cpp:406
+msgid "%1 kHz"
+msgstr "%1 kHz"
+
+#: radioview_frequencyradio.cpp:408
+msgid "%1 MHz"
+msgstr "%1 MHz"
+
+#: radioview_frequencyseeker.cpp:76
+msgid "Search for previous Radio Station"
+msgstr "Suche nach vorherigem Sender"
+
+#: radioview_frequencyseeker.cpp:77
+msgid "Search for next Radio Station"
+msgstr "Suche nach nächstem Sender"
+
+#: radioview_frequencyseeker.cpp:78
+msgid "Decrement Frequency"
+msgstr "Frequenz erniedrigen"
+
+#: radioview_frequencyseeker.cpp:79
+msgid "Increment Frequency"
+msgstr "Frequenz erhöhen"
+
+#: radioview_frequencyseeker.cpp:80
+msgid "Change Frequency"
+msgstr "Frequenz verändern"
+
+#: radioview_volume.cpp:56
+msgid "Change Volume"
+msgstr "Läutstärke verändern"
diff --git a/kradio3/plugins/gui-standard-display/po/ru.po b/kradio3/plugins/gui-standard-display/po/ru.po
new file mode 100644
index 0000000..722b790
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/po/ru.po
@@ -0,0 +1,213 @@
+# translation of ru.po to
+# translation of kradio-gui-standard-display.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 02:11+0100\n"
+"PO-Revision-Date: 2006-11-08 13:06+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file radioview_seekinterface.ui line 17
+#: rc.cpp:3 rc.cpp:25
+#, no-c-format
+msgid "RadioView_SeekInterface"
+msgstr "RadioView_SeekInterface"
+
+#. i18n: file radioview_seekinterface.ui line 45
+#: rc.cpp:7 rc.cpp:29
+#, no-c-format
+msgid "search previous station"
+msgstr "Поиск предыдущей станции"
+
+#. i18n: file radioview_seekinterface.ui line 73
+#: rc.cpp:11 rc.cpp:33
+#, no-c-format
+msgid "decrease freq. by 0.05 MHz"
+msgstr "Уменьшать частоту по 0,05 МГц"
+
+#. i18n: file radioview_seekinterface.ui line 108
+#: rc.cpp:14 rc.cpp:36
+#, no-c-format
+msgid "Frequency control"
+msgstr "Управление частотой"
+
+#. i18n: file radioview_seekinterface.ui line 129
+#: rc.cpp:18 rc.cpp:40
+#, no-c-format
+msgid "increase freq. by 0.05 MHz"
+msgstr "Увеличивать частоту по 0,05 МГц"
+
+#. i18n: file radioview_seekinterface.ui line 146
+#: rc.cpp:22 rc.cpp:44
+#, no-c-format
+msgid "search next station"
+msgstr "Поиск следующей станции"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: displaycfg.cpp:33
+msgid "Display Colors"
+msgstr "Цвета"
+
+#: displaycfg.cpp:47
+msgid "Active Text"
+msgstr "Цвет активного текста"
+
+#: displaycfg.cpp:48
+msgid "Inactive Text"
+msgstr "Цвет инертного текста"
+
+#: displaycfg.cpp:49
+msgid "Background Color"
+msgstr "Цвет фона"
+
+#: radioview.cpp:55
+msgid "Standard Display for KRadio"
+msgstr "Главное окно KRadio"
+
+#: radioview.cpp:72
+msgid "Radio Display"
+msgstr "Главное окно"
+
+#: radioview.cpp:127
+msgid "Pause KRadio"
+msgstr "Приостановить"
+
+#: radioview.cpp:133
+msgid "Start Recording"
+msgstr "Начать запись"
+
+#: radioview.cpp:141
+msgid "5 min"
+msgstr "5 минут"
+
+#: radioview.cpp:142
+msgid "10 min"
+msgstr "10 минут"
+
+#: radioview.cpp:143
+msgid "15 min"
+msgstr "четверть часа"
+
+#: radioview.cpp:144
+msgid "30 min"
+msgstr "полчаса"
+
+#: radioview.cpp:145
+msgid "60 min"
+msgstr "час"
+
+#: radioview.cpp:189
+msgid "Configure KRadio"
+msgstr "Настроить KRadio"
+
+#: radioview.cpp:190
+msgid "Power On/Off"
+msgstr "Включить/выключить"
+
+#: radioview.cpp:191
+msgid "Quit KRadio Application"
+msgstr "Закрыть KRadio"
+
+#: radioview.cpp:192
+msgid "Start/Stop Recording"
+msgstr "Начать/завершить запись"
+
+#: radioview.cpp:193
+msgid "Start/Stop Sleep Countdown"
+msgstr "Включить/выключить таймер отключения"
+
+#: radioview.cpp:194
+msgid "Show/Hide Plugins"
+msgstr "Показать/скрыть"
+
+#: radioview.cpp:195
+msgid "Select a Radio Station"
+msgstr "Выбор радиостанции из списка"
+
+#: radioview.cpp:332
+msgid "no preset defined"
+msgstr "Станция не определена"
+
+#: radioview.cpp:442 radioview.cpp:480
+msgid "Stop Recording of %1"
+msgstr "Остановить запись %1"
+
+#: radioview.cpp:553
+msgid "Display"
+msgstr "Вид"
+
+#: radioview.cpp:554
+msgid "Display Configuration"
+msgstr "Настройка внешнего вида"
+
+#: radioview.cpp:590
+msgid "set Toolbar-Flag for Display"
+msgstr ""
+
+#: radioview.cpp:593
+msgid "Common"
+msgstr "Общие"
+
+#: radioview_frequencyradio.cpp:99 radioview_frequencyradio.cpp:100
+msgid "Frequency Display"
+msgstr "Отображение частоты"
+
+#: radioview_frequencyradio.cpp:388 radioview_frequencyradio.cpp:389
+msgid "AM"
+msgstr "ДВ/СВ/КВ"
+
+#: radioview_frequencyradio.cpp:394 radioview_frequencyradio.cpp:395
+msgid "FM"
+msgstr "УКВ"
+
+#: radioview_frequencyradio.cpp:406
+msgid "%1 kHz"
+msgstr "%1 кГц"
+
+#: radioview_frequencyradio.cpp:408
+msgid "%1 MHz"
+msgstr "%1 МГц"
+
+#: radioview_frequencyseeker.cpp:76
+msgid "Search for previous Radio Station"
+msgstr "Искать станцию вниз"
+
+#: radioview_frequencyseeker.cpp:77
+msgid "Search for next Radio Station"
+msgstr "Искать станцию вверх"
+
+#: radioview_frequencyseeker.cpp:78
+msgid "Decrement Frequency"
+msgstr "Уменьшить частоту"
+
+#: radioview_frequencyseeker.cpp:79
+msgid "Increment Frequency"
+msgstr "Увеличить частоту"
+
+#: radioview_frequencyseeker.cpp:80
+msgid "Change Frequency"
+msgstr "Изменить частоту"
+
+#: radioview_volume.cpp:56
+msgid "Change Volume"
+msgstr "Изменить громкость"
diff --git a/kradio3/plugins/gui-standard-display/radioview-configuration.cpp b/kradio3/plugins/gui-standard-display/radioview-configuration.cpp
new file mode 100644
index 0000000..9a22313
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview-configuration.cpp
@@ -0,0 +1,116 @@
+/***************************************************************************
+ radioview-configuration.cpp - description
+ -------------------
+ begin : Fr Aug 15 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 "radioview-configuration.h"
+
+RadioViewConfiguration::RadioViewConfiguration(QWidget *parent)
+ : QTabWidget (parent),
+ m_dirty(true)
+{
+}
+
+RadioViewConfiguration::~RadioViewConfiguration()
+{
+}
+
+
+void RadioViewConfiguration::addTab (QWidget *child, const QString &label)
+{
+ QTabWidget::addTab(child, label);
+ QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK()));
+ QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel()));
+ QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+}
+
+
+void RadioViewConfiguration::addTab (QWidget *child, const QIconSet &iconset, const QString &label)
+{
+ QTabWidget::addTab(child, iconset, label);
+ QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK()));
+ QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel()));
+ QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+}
+
+
+void RadioViewConfiguration::addTab (QWidget *child, QTab *tab)
+{
+ QTabWidget::addTab(child, tab);
+ QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK()));
+ QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel()));
+ QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+}
+
+
+void RadioViewConfiguration::insertTab (QWidget *child, const QString &label, int index)
+{
+ QTabWidget::insertTab(child, label, index);
+ QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK()));
+ QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel()));
+ QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+}
+
+
+void RadioViewConfiguration::insertTab (QWidget *child, const QIconSet &iconset, const QString &label, int index)
+{
+ QTabWidget::insertTab(child, iconset, label, index);
+ QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK()));
+ QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel()));
+ QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+}
+
+
+void RadioViewConfiguration::insertTab (QWidget *child, QTab *tab, int index)
+{
+ QTabWidget::insertTab(child, tab, index);
+ QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK()));
+ QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel()));
+ QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+}
+
+
+void RadioViewConfiguration::removePage(QWidget *w)
+{
+ QObject::disconnect(this, SIGNAL(sigOK()), w, SLOT(slotOK()));
+ QObject::disconnect(this, SIGNAL(sigCancel()), w, SLOT(slotCancel()));
+ QObject::disconnect(w, SIGNAL(sigDirty()), this, SLOT(slotSetDirty()));
+ QTabWidget::removePage(w);
+}
+
+
+void RadioViewConfiguration::slotOK()
+{
+ if (m_dirty) {
+ emit sigOK();
+ m_dirty = false;
+ }
+}
+
+void RadioViewConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ emit sigCancel();
+ m_dirty = false;
+ }
+}
+
+void RadioViewConfiguration::slotSetDirty()
+{
+ m_dirty = true;
+}
+
+
+#include "radioview-configuration.moc"
diff --git a/kradio3/plugins/gui-standard-display/radioview-configuration.h b/kradio3/plugins/gui-standard-display/radioview-configuration.h
new file mode 100644
index 0000000..a85d4d9
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview-configuration.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ radioview-configuration.h - description
+ -------------------
+ begin : Fr Aug 15 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIOVIEW_CONFIGURATION_H
+#define KRADIO_RADIOVIEW_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+
+#include <qtabwidget.h>
+
+class RadioViewConfiguration : public QTabWidget
+{
+Q_OBJECT
+public :
+ RadioViewConfiguration(QWidget *parent = NULL);
+ ~RadioViewConfiguration();
+
+ void addTab (QWidget *child, const QString &label);
+ void addTab (QWidget *child, const QIconSet &iconset, const QString &label);
+ void addTab (QWidget *child, QTab *tab);
+ void insertTab (QWidget *child, const QString &label, int index = -1);
+ void insertTab (QWidget *child, const QIconSet &iconset, const QString &label, int index = -1);
+ void insertTab (QWidget *child, QTab *tab, int index = -1);
+ void removePage(QWidget *w);
+
+public slots:
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+signals:
+
+ void sigOK();
+ void sigCancel();
+
+protected:
+ bool m_dirty;
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/gui-standard-display/radioview.cpp b/kradio3/plugins/gui-standard-display/radioview.cpp
new file mode 100644
index 0000000..e1fd8e4
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview.cpp
@@ -0,0 +1,807 @@
+/***************************************************************************
+ 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 <qwidgetstack.h>
+#include <qlayout.h>
+#include <qtoolbutton.h>
+#include <qslider.h>
+#include <qfile.h>
+#include <qtooltip.h>
+#include <qcheckbox.h>
+#include <qimage.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 QString &name)
+ : QWidget(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;
+
+ QBoxLayout *l01 = new QBoxLayout(this, QBoxLayout::LeftToRight, /*spacing=*/3);
+ l01->setMargin(1);
+ l01->setSpacing(2);
+ widgetStacks[clsRadioSound] = new QWidgetStack (this);
+ l01->addWidget(widgetStacks[clsRadioSound]);
+
+ QBoxLayout *l02 = new QBoxLayout(l01, QBoxLayout::Down);
+ QBoxLayout *l03 = new QBoxLayout(l02, QBoxLayout::LeftToRight);
+ comboStations = new KComboBox (this);
+ l02->addWidget (comboStations);
+
+ QBoxLayout *l05 = new QBoxLayout(l03, QBoxLayout::Down);
+ widgetStacks[clsRadioDisplay] = new QWidgetStack (this);
+ l05->addWidget(widgetStacks[clsRadioDisplay]);
+ widgetStacks[clsRadioSeek] = new QWidgetStack (this);
+ l05->addWidget(widgetStacks[clsRadioSeek]);
+
+ QGridLayout *l04 = new QGridLayout (l03, /*rows=*/ 3, /*cols=*/ 2);
+ btnPower = new QToolButton(this);
+ btnPower->setToggleButton(true);
+ btnRecording = new QToolButton(this);
+ btnRecording->setToggleButton(true);
+ btnConfigure = new QToolButton(this);
+ btnConfigure->setToggleButton(true);
+ btnQuit = new QToolButton(this);
+ btnSnooze = new QToolButton(this);
+ btnSnooze->setToggleButton(true);
+ btnPlugins = new QToolButton(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, SLOT(slotPause()));
+ btnPower->setPopupDelay(200);
+
+ m_RecordingMenu = new KPopupMenu(btnRecording);
+ m_RecordingMenu->insertItem(SmallIcon("kradio_record"),
+ i18n("Start Recording"),
+ POPUP_ID_START_RECORDING_DEFAULT);
+ QObject::connect(m_RecordingMenu, SIGNAL(activated(int)),
+ this, SLOT(slotRecordingMenu(int)));
+ btnRecording->setPopup(m_RecordingMenu);
+
+
+ m_SnoozeMenu = new KPopupMenu(btnSnooze);
+ m_SnoozeMenu->insertItem(i18n("5 min"), this, SLOT(slotSnooze(int)), 0, 5);
+ m_SnoozeMenu->insertItem(i18n("10 min"), this, SLOT(slotSnooze(int)), 0, 10);
+ m_SnoozeMenu->insertItem(i18n("15 min"), this, SLOT(slotSnooze(int)), 0, 15);
+ m_SnoozeMenu->insertItem(i18n("30 min"), this, SLOT(slotSnooze(int)), 0, 30);
+ m_SnoozeMenu->insertItem(i18n("60 min"), this, 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(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred));
+ widgetStacks[clsRadioDisplay]->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
+ widgetStacks[clsRadioSeek] ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
+ comboStations ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
+ comboStations->setMinimumHeight(28);
+
+
+ QObject::connect(btnPower, SIGNAL(toggled(bool)),
+ this, SLOT(slotPower(bool)));
+ QObject::connect(btnQuit, SIGNAL(clicked()),
+ kapp, SLOT(quit()));
+ QObject::connect(btnConfigure, SIGNAL(toggled(bool)),
+ this, SLOT(slotConfigure(bool)));
+ QObject::connect(btnRecording, SIGNAL(clicked()),
+ this, SLOT(slotRecord()));
+ QObject::connect(btnSnooze, SIGNAL(toggled(bool)),
+ this, SLOT(slotSnooze(bool)));
+ QObject::connect(comboStations, SIGNAL(activated(int)),
+ this, SLOT(slotComboStationSelected(int)));
+ QObject::connect(btnPlugins, SIGNAL(clicked()),
+ this, SLOT(slotBtnPluginsClicked()));
+
+ // tooltips
+
+ QToolTip::add(btnConfigure, i18n("Configure KRadio"));
+ QToolTip::add(btnPower, i18n("Power On/Off"));
+ QToolTip::add(btnQuit, i18n("Quit KRadio Application"));
+ QToolTip::add(btnRecording, i18n("Start/Stop Recording"));
+ QToolTip::add(btnSnooze, i18n("Start/Stop Sleep Countdown"));
+ QToolTip::add(btnPlugins, i18n("Show/Hide Plugins"));
+ QToolTip::add(comboStations, i18n("Select a Radio Station"));
+
+ // testing
+ addElement (new RadioViewFrequencyRadio (this, QString::null));
+ addElement (new RadioViewVolume(this, QString::null));
+ addElement (new RadioViewFrequencySeeker(this, QString::null));
+
+ autoSetCaption();
+}
+
+
+RadioView::~RadioView ()
+{
+ QPtrListIterator<QObject> 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, QPoint(0, 0), true);
+ QObject::connect(e, SIGNAL(destroyed(QObject*)),
+ this, SLOT(removeElement(QObject*)));
+ 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());
+
+ QPtrListIterator<QObject> it(configPages);
+ for (; it.current(); ++it) {
+ addConfigurationTabFor(e, (QTabWidget *)it.current());
+ }
+
+ selectTopWidgets();
+
+ return true;
+}
+
+
+bool RadioView::removeElement (QObject *_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();
+ QObject::disconnect(e, SIGNAL(destroyed(QObject*)),
+ this, SLOT(removeElement(QObject*)));
+ 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();
+ QString icon = stn->iconName();
+ if (icon.length() && QFile(icon).exists()) {
+ QImage 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;
+
+ QString 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)) {
+ QString 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 QDateTime &)
+{
+ 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(QString("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(QString("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(c);
+ QObject::connect(c, SIGNAL(destroyed(QObject *)),
+ this, SLOT(slotConfigPageDeleted(QObject *)));
+
+ return ConfigPageInfo(
+ c,
+ i18n("Display"),
+ i18n("Display Configuration"),
+ "openterm"
+ );
+}
+
+
+void RadioView::addConfigurationTabFor(RadioViewElement *e, QTabWidget *c)
+{
+ if (!e || !c)
+ return;
+
+ ConfigPageInfo inf = e->createConfigurationPage();
+
+ if (inf.page) {
+
+ if (inf.iconName.length()) {
+ c->addTab(inf.page, QIconSet(SmallIconSet(inf.iconName)), inf.itemName);
+ } else {
+ c->addTab(inf.page, inf.itemName);
+ }
+
+ elementConfigPages.push_back(ElementCfg(e, inf.page));
+ QObject::connect(inf.page, SIGNAL(destroyed(QObject *)),
+ this, SLOT(slotElementConfigPageDeleted(QObject *)));
+ }
+}
+
+
+void RadioView::addCommonConfigurationTab(QTabWidget *c)
+{
+ if (!c)
+ return;
+
+ QFrame *f = new QFrame(c);
+ QVBoxLayout *l = new QVBoxLayout(f, 10);
+
+ l->addWidget(new QCheckBox(i18n("set Toolbar-Flag for Display"), f));
+ l->addItem(new QSpacerItem(1, 3, QSizePolicy::Fixed, QSizePolicy::Expanding));
+
+ c->addTab(f, i18n("Common"));
+
+ elementConfigPages.push_back(ElementCfg(f));
+ QObject::connect(f, SIGNAL(destroyed(QObject *)),
+ this, SLOT(slotElementConfigPageDeleted(QObject *)));
+}
+
+
+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)
+{
+ QWidget *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(QObject *o)
+{
+ configPages.remove(o);
+}
+
+
+void RadioView::slotElementConfigPageDeleted(QObject *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();
+ QWidget::show();
+}
+
+
+void RadioView::showOnOrgDesktop()
+{
+ WidgetPluginBase::pShowOnOrgDesktop();
+ //QWidget::show();
+}
+
+
+
+void RadioView::hide()
+{
+ WidgetPluginBase::pHide();
+ QWidget::hide();
+}
+
+
+void RadioView::showEvent(QShowEvent *e)
+{
+ QWidget::showEvent(e);
+ WidgetPluginBase::pShowEvent(e);
+}
+
+
+void RadioView::hideEvent(QHideEvent *e)
+{
+ QWidget::hideEvent(e);
+ WidgetPluginBase::pHideEvent(e);
+}
+
+
+void RadioView::autoSetCaption()
+{
+ const RadioStation &rs = queryCurrentStation();
+ setCaption((queryIsPowerOn() && rs.isValid()) ? rs.longName() : QString("KRadio"));
+}
+
+
+
+
+#include "radioview.moc"
diff --git a/kradio3/plugins/gui-standard-display/radioview.h b/kradio3/plugins/gui-standard-display/radioview.h
new file mode 100644
index 0000000..6cddc26
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview.h
@@ -0,0 +1,207 @@
+/***************************************************************************
+ radioview.h - 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIOVIEW_H
+#define KRADIO_RADIOVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qobjectlist.h>
+
+#include "../../src/include/radio_interfaces.h"
+#include "../../src/include/radiodevicepool_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "../../src/include/timecontrol_interfaces.h"
+#include "../../src/include/widgetplugins.h"
+#include "radioview_element.h"
+
+class QWidgetStack;
+class QToolButton;
+class KComboBox;
+class QTabWidget;
+class KPopupMenu;
+
+
+
+class RadioView : public QWidget,
+ public WidgetPluginBase,
+ public IRadioClient,
+ public IRadioDevicePoolClient,
+ public ISoundStreamClient,
+ public ITimeControlClient
+{
+Q_OBJECT
+public:
+
+ RadioView(const QString &name);
+ virtual ~RadioView();
+
+ virtual QString pluginClassName() const { return "RadioView"; }
+
+ const QString &name() const { return PluginBase::name(); }
+ QString &name() { return PluginBase::name(); }
+
+ // WidgetPluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ virtual void noticeWidgetPluginShown(WidgetPluginBase *p, bool shown);
+ virtual void noticePluginsChanged(const PluginList &);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+public slots:
+ // connects destroy-msg with remove-function
+ bool addElement (RadioViewElement *);
+ bool removeElement (QObject *);
+
+protected:
+ void selectTopWidgets();
+
+
+ // IRadioClient
+
+RECEIVERS:
+ bool noticePowerChanged(bool on);
+ bool noticeStationChanged (const RadioStation &, int idx);
+ bool noticeStationsChanged(const StationList &sl);
+ bool noticePresetFileChanged(const QString &/*f*/) { return false; }
+
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID id);
+
+ // IRadioDevicePoolClient
+
+RECEIVERS:
+ bool noticeActiveDeviceChanged(IRadioDevice *rd);
+ bool noticeDevicesChanged(const QPtrList<IRadioDevice> &) { return false; }
+ bool noticeDeviceDescriptionChanged(const QString &) { return false; }
+
+ // ISoundStreamClient
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool startRecordingWithFormat(SoundStreamID /*id*/,
+ const SoundFormat &/*proposed_format*/,
+ SoundFormat &/*real_format*/);
+ bool stopRecording(SoundStreamID /*id*/);
+
+ bool noticeSoundStreamChanged(SoundStreamID id);
+
+ // ITimeControlClient
+
+RECEIVERS:
+ bool noticeAlarmsChanged(const AlarmVector &) { return false; }
+ bool noticeAlarm(const Alarm &) { return false; }
+ bool noticeNextAlarmChanged(const Alarm *) { return false; }
+ bool noticeCountdownStarted(const QDateTime &end);
+ bool noticeCountdownStopped();
+ bool noticeCountdownZero();
+ bool noticeCountdownSecondsChanged(int) { return false; }
+
+protected slots:
+
+ void slotPower (bool on);
+ void slotPause();
+ void slotConfigure (bool show);
+ void slotRecord ();
+ void slotSnooze (bool start);
+ void slotSnooze (int time);
+ void slotRecordingMenu(int i);
+ void slotBtnPluginsClicked();
+ void slotComboStationSelected(int);
+
+ void slotConfigPageDeleted(QObject*);
+ void slotElementConfigPageDeleted(QObject*);
+
+public slots:
+
+ void toggleShown() { WidgetPluginBase::pToggleShown(); }
+ void showOnOrgDesktop();
+ void show();
+ void hide();
+
+protected:
+ virtual void showEvent(QShowEvent *);
+ virtual void hideEvent(QHideEvent *);
+
+ virtual void autoSetCaption();
+
+ const QWidget *getWidget() const { return this; }
+ QWidget *getWidget() { return this; }
+
+ void addConfigurationTabFor(RadioViewElement *, QTabWidget *);
+ void addCommonConfigurationTab(QTabWidget *);
+
+protected:
+ bool enableToolbarFlag;
+
+ QToolButton *btnPower;
+ QToolButton *btnConfigure;
+ QToolButton *btnQuit;
+ QToolButton *btnRecording;
+ QToolButton *btnSnooze;
+ QToolButton *btnPlugins;
+ KComboBox *comboStations;
+
+ struct ElementCfg
+ {
+ RadioViewElement *element;
+ QObject *cfg;
+ ElementCfg() : element(NULL), cfg(NULL) {}
+ ElementCfg(RadioViewElement *e, QObject *w) : element(e), cfg(w) {}
+ ElementCfg(RadioViewElement *e) : element(e), cfg(NULL) {}
+ ElementCfg(QObject *w) : element(NULL), cfg(w) {}
+ bool operator == (const ElementCfg &x) const;
+ };
+
+ typedef QPtrList<RadioViewElement> ElementList;
+ typedef QPtrListIterator<RadioViewElement> ElementListIterator;
+ typedef QValueList<ElementCfg> ElementCfgList;
+ typedef QValueListIterator<ElementCfg> ElementCfgListIterator;
+
+ ElementList elements;
+ ElementCfgList elementConfigPages;
+ QObjectList configPages;
+ QWidgetStack * widgetStacks[clsClassMAX];
+ float maxUsability[clsClassMAX];
+
+ IRadioDevice *currentDevice;
+
+ KPopupMenu *m_RecordingMenu;
+ KPopupMenu *m_pauseMenu;
+ KPopupMenu *m_SnoozeMenu;
+ int m_NextRecordingMenuID;
+ QMap<int, SoundStreamID> m_MenuID2StreamID;
+ QMap<SoundStreamID, int> m_StreamID2MenuID;
+
+ KPopupMenu *m_PluginMenu;
+ QMap<WidgetPluginBase *, int> m_Plugins2MenuID;
+};
+
+
+
+
+#endif
diff --git a/kradio3/plugins/gui-standard-display/radioview_element.cpp b/kradio3/plugins/gui-standard-display/radioview_element.cpp
new file mode 100644
index 0000000..9c3396f
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_element.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ radioview_element.cpp - description
+ -------------------
+ begin : Fre Jun 20 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 "radioview_element.h"
+
+RadioViewElement::RadioViewElement (QWidget * /*parent*/, const QString & /*name*/,
+ RadioViewClass cls)
+ : myClass(cls)
+{
+}
+
+
+RadioViewElement::~RadioViewElement()
+{
+}
+
+
+
+
+#include "radioview_element.moc"
diff --git a/kradio3/plugins/gui-standard-display/radioview_element.h b/kradio3/plugins/gui-standard-display/radioview_element.h
new file mode 100644
index 0000000..11c77ac
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_element.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ radioview_element.h - description
+ -------------------
+ begin : Fre Jun 20 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIOVIEW_ELEMENT_H
+#define KRADIO_RADIOVIEW_ELEMENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qframe.h>
+#include "../../src/include/interfaces.h"
+#include "../../src/include/plugins.h"
+
+enum RadioViewClass { clsRadioSound = 0,
+ clsRadioSeek,
+ clsRadioDisplay,
+ clsClassMAX
+ };
+
+
+// Defaults to an empty element
+class RadioViewElement : public QFrame,
+ public virtual Interface
+{
+Q_OBJECT
+public:
+ RadioViewElement (QWidget *parent, const QString &name, RadioViewClass myClass);
+ virtual ~RadioViewElement();
+
+ bool connectI (Interface *) { return false; } // default behaviour, please overwrite in derived class
+ bool disconnectI(Interface *) { return false; } // default behaviour, please overwrite in derived class
+
+ float getUsability (Interface *) const { return 0.01; } // 0 <= Usability <= 1, used to decide wich Element to use
+ // should be overwritten ;)
+
+ RadioViewClass getClass() const { return myClass; }
+
+ // Configuration ??
+ virtual ConfigPageInfo createConfigurationPage() { return ConfigPageInfo(); }
+
+ virtual void saveState (KConfig *) const {}
+ virtual void restoreState (KConfig *) {}
+
+
+protected :
+
+ RadioViewClass myClass;
+};
+
+
+#endif
diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyradio.cpp b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.cpp
new file mode 100644
index 0000000..8c6d15d
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.cpp
@@ -0,0 +1,443 @@
+/***************************************************************************
+ kradiodisplay.cpp - description
+ -------------------
+ begin : Mit Jan 29 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 "../../src/include/utils.h"
+
+#include <qpainter.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <kimageeffect.h> // fading, blending, ...
+#include <kpixmapio.h> // fast conversion between QPixmap/QImage
+#include "radioview_frequencyradio.h"
+#include "displaycfg.h"
+
+RadioViewFrequencyRadio::RadioViewFrequencyRadio(QWidget *parent, const QString &name )
+ : RadioViewElement(parent, name, clsRadioDisplay),
+ m_power(false),
+ m_valid(false),
+ m_frequency(0),
+ m_quality(0.0),
+ m_stereo(false)
+{
+ setFrameStyle(Box | Sunken);
+ setLineWidth(1);
+ setMidLineWidth(1);
+
+
+ // set some sensless default colors
+ // real values are read in restoreState
+ setDisplayColors(QColor(20, 244, 20),
+ QColor(10, 117, 10).light(75),
+ QColor(10, 117, 10));
+ setDisplayFont(QFont("Helvetica"));
+
+}
+
+
+RadioViewFrequencyRadio::~RadioViewFrequencyRadio(){
+}
+
+
+float RadioViewFrequencyRadio::getUsability (Interface *i) const
+{
+ if (dynamic_cast<IFrequencyRadio*>(i))
+ return 1.0;
+ else
+ return 0.0;
+}
+
+
+void RadioViewFrequencyRadio::saveState (KConfig *config) const
+{
+ config->writeEntry("frequency-view-colorActiveText", m_colorActiveText);
+ config->writeEntry("frequency-view-colorInactiveText", m_colorInactiveText);
+ config->writeEntry("frequency-view-colorButton", m_colorButton);
+ config->writeEntry("frequency-view-font", m_font);
+}
+
+
+void RadioViewFrequencyRadio::restoreState (KConfig *config)
+{
+ QColor defaultActive (20, 244, 20),
+ defaultInactive(QColor(10, 117, 10).light(75)),
+ defaultButton (10, 117, 10);
+ QFont defaultFont ("Helvetica");
+ QColor a, b, c;
+ QFont f;
+ a = config->readColorEntry ("frequency-view-colorActiveText",
+ &defaultActive);
+ b = config->readColorEntry ("frequency-view-colorInactiveText",
+ &defaultInactive);
+ c = config->readColorEntry ("frequency-view-colorButton",
+ &defaultButton);
+ f = config->readFontEntry ("frequency-view-font",
+ &defaultFont);
+ setDisplayColors(a, b, c);
+ setDisplayFont(f);
+}
+
+
+ConfigPageInfo RadioViewFrequencyRadio::createConfigurationPage()
+{
+ DisplayConfiguration *a = new DisplayConfiguration(NULL);
+ connectI(a);
+ return ConfigPageInfo (a,
+ i18n("Frequency Display"),
+ i18n("Frequency Display"),
+ QString::null
+ );
+}
+
+
+// Interface
+
+bool RadioViewFrequencyRadio::connectI(Interface *i)
+{
+ bool o = IDisplayCfg::connectI(i);
+ bool c = ISoundStreamClient::connectI(i);
+ if (dynamic_cast<IFrequencyRadio *>(i)) {
+
+ bool a = IRadioDeviceClient::connectI(i);
+ bool b = IFrequencyRadioClient::connectI(i);
+ return o || a || b || c;
+
+ } else {
+ return o || c;
+ }
+}
+
+
+bool RadioViewFrequencyRadio::disconnectI(Interface *i)
+{
+ // no check for IFrequencyRadio, it's just a disconnect
+
+ bool a = IRadioDeviceClient::disconnectI(i);
+ bool b = IFrequencyRadioClient::disconnectI(i);
+ bool c = ISoundStreamClient::disconnectI(i);
+ bool o = IDisplayCfg::disconnectI(i);
+
+ return a || b || c || o;
+}
+
+void RadioViewFrequencyRadio::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_notifySignalQualityChanged(this);
+ s->register4_notifyStereoChanged(this);
+ }
+}
+
+// IDisplayCfg
+
+bool RadioViewFrequencyRadio::setDisplayColors(const QColor &activeText,
+ const QColor &inactiveText,
+ const QColor &button)
+{
+ bool change = (activeText != m_colorActiveText || inactiveText != m_colorInactiveText || button != m_colorButton);
+
+ m_colorActiveText = activeText;
+ m_colorInactiveText = inactiveText;
+ m_colorButton = button;
+
+ QPalette pl = palette();
+ QColorGroup cg = pl.inactive();
+
+ QBrush fg = cg.brush(QColorGroup::Foreground),
+ btn = cg.brush(QColorGroup::Button),
+ lgt = cg.brush(QColorGroup::Light),
+ drk = cg.brush(QColorGroup::Dark),
+ mid = cg.brush(QColorGroup::Mid),
+ txt = cg.brush(QColorGroup::Text),
+ btx = cg.brush(QColorGroup::BrightText),
+ bas = cg.brush(QColorGroup::Base),
+ bg = cg.brush(QColorGroup::Background);
+
+ fg.setColor (m_colorActiveText);
+ btn.setColor(m_colorButton);
+ lgt.setColor(m_colorButton.light(180));
+ drk.setColor(m_colorButton.light( 50));
+ mid.setColor(m_colorInactiveText);
+ txt.setColor(m_colorActiveText);
+ btx.setColor(m_colorActiveText);
+ bas.setColor(m_colorButton);
+ bg.setColor (m_colorButton);
+
+ QColorGroup ncg(fg, btn, lgt, drk, mid, txt, btx, bas, bg);
+ pl.setInactive(ncg);
+ pl.setActive(ncg);
+ setPalette(pl);
+
+ if (parentWidget() && parentWidget()->backgroundPixmap() ){
+ KPixmapIO io;
+ QImage i = io.convertToImage(*parentWidget()->backgroundPixmap());
+ KImageEffect::fade(i, 0.5, colorGroup().color(QColorGroup::Dark));
+ setPaletteBackgroundPixmap(io.convertToPixmap(i));
+ setBackgroundOrigin(WindowOrigin);
+ } else {
+ setBackgroundColor(colorGroup().color(QColorGroup::Button));
+ }
+
+ if (change)
+ notifyDisplayColorsChanged(m_colorActiveText, m_colorInactiveText, m_colorButton);
+ return true;
+}
+
+bool RadioViewFrequencyRadio::setDisplayFont (const QFont &f)
+{
+ if (m_font != f) {
+ m_font = f;
+ notifyDisplayFontChanged(m_font);
+ RadioViewElement::setFont(f);
+ }
+ return true;
+}
+
+// IRadioDeviceClient
+
+
+bool RadioViewFrequencyRadio::noticePowerChanged (bool on, const IRadioDevice */*sender*/)
+{
+ m_power = on;
+
+ SoundStreamID ssid = queryCurrentSoundStreamID();
+ float q = 0.0;
+ bool s = false;
+ querySignalQuality(ssid, q);
+ noticeSignalQualityChanged(ssid, q);
+ queryIsStereo(ssid, s);
+ noticeStereoChanged(ssid, s);
+
+ repaint();
+ return true;
+}
+
+
+bool RadioViewFrequencyRadio::noticeStationChanged (const RadioStation &, const IRadioDevice */*sender*/)
+{
+ return false; // we don't care
+}
+
+
+bool RadioViewFrequencyRadio::noticeDescriptionChanged (const QString &, const IRadioDevice */*sender*/)
+{
+ return false; // we don't care
+}
+
+
+// IRadioSoundClient
+
+bool RadioViewFrequencyRadio::noticeSignalQualityChanged(SoundStreamID id, float q)
+{
+ if (queryCurrentSoundStreamID() != id)
+ return false;
+ m_quality = q;
+ repaint ();
+ return true;
+}
+
+
+bool RadioViewFrequencyRadio::noticeStereoChanged(SoundStreamID id, bool s)
+{
+ if (queryCurrentSoundStreamID() != id)
+ return false;
+ m_stereo = s;
+ repaint ();
+ return true;
+}
+
+
+
+
+// IFrequencyRadioClient
+
+
+bool RadioViewFrequencyRadio::noticeFrequencyChanged(float f, const RadioStation *)
+{
+ m_frequency = f;
+ repaint ();
+ return true;
+}
+
+
+bool RadioViewFrequencyRadio::noticeMinMaxFrequencyChanged(float /*min*/, float /*max*/)
+{
+ return false; // we don't care
+}
+
+
+bool RadioViewFrequencyRadio::noticeDeviceMinMaxFrequencyChanged(float /*min*/, float /*max*/)
+{
+ return false; // we don't care
+}
+
+
+bool RadioViewFrequencyRadio::noticeScanStepChanged(float /*s*/)
+{
+ return false; // we don't care
+}
+
+
+
+void RadioViewFrequencyRadio::drawContents(QPainter *paint)
+{
+ if (!paint) return;
+
+ QRect r = contentsRect();
+
+ int margin = QMAX(4, QMIN(r.width() / 50, r.height() / 50)),
+ tmp = QMIN(r.height(), (r.width() - 2*margin) / 4),
+ xd_st = QMIN((r.height() - margin * 2) / 3, tmp/3),
+ xw = QMIN(tmp / 2, xd_st * 3 / 2),
+ penw = QMAX(1, xw / 25),
+ xh_st = xd_st,
+ xx_st = r.x() + margin + xw + 2 * margin + penw/2,
+ xy_st = r.y() + margin + penw/2,
+
+ xx_am = xx_st,
+ xy_am = xy_st + xh_st + margin / 2,
+ xh_am = (r.bottom() - margin - xy_am + 1 - margin/2) / 2,
+
+ xx_fm = xx_am,
+ xy_fm = xy_am + xh_am + margin/2,
+ xh_fm = xh_am,
+
+ xh_sg = r.height() - margin * 2,
+ xx_sg = r.x() + margin,
+ xy_sg = r.y() + margin;
+
+ QPen activePen (colorGroup().color(QColorGroup::Text), penw);
+ QPen inactivePen (colorGroup().color(QColorGroup::Mid), penw);
+ QBrush activeBrush = colorGroup().brush(QColorGroup::Text);
+ QBrush inactiveBrush = colorGroup().brush(QColorGroup::Mid);
+
+ // draw stereo symbol
+ paint->setPen( (m_stereo && m_power) ? activePen : inactivePen);
+ paint->drawArc((int)xx_st, (int)xy_st,
+ (int)(xd_st - penw), (int)(xd_st - penw),
+ 0, 360*16);
+ paint->drawArc((int)(xx_st + xd_st/2), (int)xy_st,
+ (int)(xd_st - penw), (int)(xd_st - penw),
+ 0, 360*16);
+
+ // draw signal quality symbol
+ float cx = xx_sg,
+ cy = xy_sg,
+ cw = xw,
+ ch = xw;
+
+ float open_a = 30.0;
+ // outer circle
+ paint->setPen( (m_quality > 0.75 && m_power) ? activePen : inactivePen);
+ paint->drawArc((int)rint(cx), (int)rint(cy),
+ (int)rint(cw), (int)rint(ch),
+ (int)(-90+open_a)*16, (int)(360 - 2*open_a)*16
+ );
+
+ // mid circle
+ paint->setPen( (m_quality > 0.50 && m_power) ? activePen : inactivePen);
+ cx += (float)xw/5.0; cy += (float)xw/5.0;
+ cw -= (float)xw/2.5; ch -= (float)xw/2.5;
+ paint->drawArc((int)rint(cx), (int)rint(cy),
+ (int)rint(cw), (int)rint(ch),
+ (int)(-90+open_a)*16, (int)(360 - 2*open_a)*16
+ );
+
+ // inner circle
+ paint->setPen( (m_quality > 0.25 && m_power) ? activePen : inactivePen);
+ cx += (float)xw/5.0; cy += (float)xw/5.0;
+ cw -= (float)xw/2.5; ch -= (float)xw/2.5;
+ paint->drawArc((int)rint(cx), (int)rint(cy),
+ (int)rint(cw), (int)rint(ch),
+ (int)(-90+open_a)*16, (int)(360 - 2*open_a)*16
+ );
+
+ // triangle
+ QPen tmppen = (m_quality > 0.1 && m_power) ? activePen : inactivePen;
+ tmppen.setWidth(1);
+ paint->setPen(tmppen);
+ paint->setBrush( (m_quality > 0.1 && m_power) ? activeBrush : inactiveBrush);
+ QPointArray pts(3);
+ pts.setPoint(0, (int)(xx_sg + xw / 4), (int)(xy_sg + xh_sg - penw/2));
+ pts.setPoint(1, (int)(xx_sg + xw *3/4), (int)(xy_sg + xh_sg - penw/2));
+ pts.setPoint(2, (int)(xx_sg + xw / 2), (int)(xy_sg + xw/2 + penw));
+ paint->drawConvexPolygon(pts);
+
+
+
+ // AM/FM display
+
+ QFont f = m_font;
+ paint->setPen ( (m_frequency <= 10 && m_power) ? activePen : inactivePen);
+ f.setPixelSize(xh_am);
+ paint->setFont(f);
+ paint->drawText(xx_am, xy_am + xh_am - 1, i18n("AM"));
+ int xw_am = QFontMetrics(f).width(i18n("AM"));
+
+ paint->setPen ( (m_frequency > 10 && m_power) ? activePen : inactivePen);
+ f.setPixelSize(xh_fm);
+ paint->setFont(f);
+ paint->drawText(xx_fm, xy_fm + xh_fm - 1, i18n("FM"));
+ int xw_fm = QFontMetrics(f).width(i18n("FM"));
+
+ int xx_f = QMAX(xx_fm + xw_fm, QMAX(xw_am + xx_am, QMAX(xx_st + xw, xw + xx_sg))) + margin,
+ xy_f = r.y() + margin,
+ xw_f = r.right() - margin - xx_f + 1,
+ xh_f = r.bottom() - margin - xy_f + 1;
+
+ // Frequency Display
+
+ QString s;
+ if (m_frequency < 10) {
+ s = i18n("%1 kHz").arg(KGlobal::locale()->formatNumber((int)(m_frequency * 1000), 0));
+ } else {
+ s = i18n("%1 MHz").arg(KGlobal::locale()->formatNumber(m_frequency, 2));
+ }
+
+ float pxs = xh_f;
+ paint->setPen ( m_power ? activePen : inactivePen);
+ f.setPixelSize((int)pxs);
+ int n = 30;
+ while (1) {
+ QFontMetrics fm(f);
+ int sw = fm.boundingRect(xx_f, xy_f, xw_f, xh_f, Qt::AlignRight | Qt::AlignVCenter, s).width();
+ if (sw <= xw_f || --n <= 0) break;
+
+ float fact = (float)xw_f / (float)sw;
+ pxs = QMIN(pxs - 1, pxs * fact);
+ f.setPixelSize(QMAX(1,(int)pxs));
+ }
+ paint->setFont(f);
+ paint->drawText(xx_f, xy_f, xw_f, xh_f, Qt::AlignRight | Qt::AlignVCenter, s);
+}
+
+
+
+
+
+
+void RadioViewFrequencyRadio::reparent (QWidget *prnt,
+ WFlags f,
+ const QPoint &p,
+ bool showIt)
+{
+ RadioViewElement::reparent(prnt, f, p, showIt);
+ setDisplayColors(m_colorActiveText, m_colorInactiveText, m_colorButton);
+}
+
+
+#include "radioview_frequencyradio.moc"
diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyradio.h b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.h
new file mode 100644
index 0000000..795eae1
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+ kradiodisplay.h - description
+ -------------------
+ begin : Mit Jan 29 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIOVIEW_FREQUENCYRADIO_H
+#define KRADIO_RADIOVIEW_FREQUENCYRADIO_H
+
+#include "../../src/include/radiodevice_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "radioview_element.h"
+#include "displaycfg_interfaces.h"
+
+/**
+ *@author Martin Witte
+ */
+
+class RadioViewFrequencyRadio : public RadioViewElement, // is a QObject, must be first
+ public IRadioDeviceClient,
+ public IFrequencyRadioClient,
+ public ISoundStreamClient,
+ public IDisplayCfg
+{
+Q_OBJECT
+public:
+ RadioViewFrequencyRadio(QWidget *parent, const QString &name);
+ ~RadioViewFrequencyRadio();
+
+ float getUsability (Interface *) const;
+
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ ConfigPageInfo createConfigurationPage();
+
+// Interface
+
+ bool connectI (Interface *);
+ bool disconnectI(Interface *);
+
+// IDisplayCfg
+
+RECEIVERS:
+ bool setDisplayColors(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd);
+ bool setDisplayFont (const QFont &f);
+
+ANSWERS:
+ const QColor &getDisplayActiveColor() const { return m_colorActiveText; }
+ const QColor &getDisplayInactiveColor() const { return m_colorInactiveText; }
+ const QColor &getDisplayBkgndColor() const { return m_colorButton; }
+ const QFont &getDisplayFont() const { return m_font; }
+
+// IRadioDeviceClient
+RECEIVERS:
+ bool noticePowerChanged (bool on, const IRadioDevice *sender = NULL);
+ bool noticeStationChanged (const RadioStation &, const IRadioDevice *sender = NULL);
+ bool noticeDescriptionChanged (const QString &, const IRadioDevice *sender = NULL);
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/, const IRadioDevice */*sender*/) { return false; }
+
+// ISoundStreamClient
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool noticeSignalQualityChanged(SoundStreamID id, float q);
+ bool noticeStereoChanged(SoundStreamID id, bool s);
+
+// IFrequencyRadioClient
+RECEIVERS:
+ bool noticeFrequencyChanged(float f, const RadioStation *s);
+ bool noticeMinMaxFrequencyChanged(float min, float max);
+ bool noticeDeviceMinMaxFrequencyChanged(float min, float max);
+ bool noticeScanStepChanged(float s);
+
+// own stuff ;)
+
+public:
+
+ void reparent (QWidget *parent, WFlags f, const QPoint &p, bool showIt = FALSE);
+
+protected:
+
+ void drawContents(QPainter *p);
+
+protected:
+
+ QColor m_colorActiveText, m_colorInactiveText, m_colorButton;
+ QFont m_font;
+
+ bool m_power;
+ bool m_valid;
+ float m_frequency;
+ float m_quality;
+ bool m_stereo;
+};
+
+#endif
diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.cpp b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.cpp
new file mode 100644
index 0000000..938939a
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.cpp
@@ -0,0 +1,250 @@
+/***************************************************************************
+ radioview_frequencyseeker.cpp - description
+ -------------------
+ begin : Fre Jun 20 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 <math.h>
+#include <qlayout.h>
+#include <qslider.h>
+#include <qtoolbutton.h>
+#include <qaccel.h>
+#include <qtooltip.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "radioview_frequencyseeker.h"
+
+RadioViewFrequencySeeker::RadioViewFrequencySeeker(QWidget *parent, const QString &name)
+ : RadioViewElement(parent, name, clsRadioSeek),
+ m_btnSearchLeft(NULL),
+ m_btnStepLeft(NULL),
+ m_btnStepRight(NULL),
+ m_btnSearchRight(NULL),
+ m_sldFrequency(NULL),
+ m_ignoreChanges(false)
+{
+ QBoxLayout *l = new QBoxLayout(this, QBoxLayout::LeftToRight, /*spacing=*/ 3);
+ l->setMargin(0);
+
+ m_sldFrequency = new QSlider(Qt::Horizontal, this);
+ m_btnSearchLeft = new QToolButton(this);
+ m_btnSearchRight = new QToolButton(this);
+ m_btnStepLeft = new QToolButton(this);
+ m_btnStepRight = new QToolButton(this);
+
+ m_btnSearchLeft ->setToggleButton(true);
+ m_btnSearchRight->setToggleButton(true);
+ m_sldFrequency->setPageStep(1);
+
+ m_btnSearchLeft ->setIconSet(SmallIconSet("2leftarrow"));
+ m_btnSearchRight->setIconSet(SmallIconSet("2rightarrow"));
+ m_btnStepLeft ->setIconSet(SmallIconSet("1leftarrow"));
+ m_btnStepRight ->setIconSet(SmallIconSet("1rightarrow"));
+
+ l->addWidget (m_btnSearchLeft);
+ l->addWidget (m_btnStepLeft);
+ l->addWidget (m_sldFrequency);
+ l->addWidget (m_btnStepRight);
+ l->addWidget (m_btnSearchRight);
+
+ QObject::connect(m_sldFrequency, SIGNAL(valueChanged(int)),
+ this, SLOT(slotSliderChanged(int)));
+ QObject::connect(m_btnSearchLeft, SIGNAL(toggled(bool)),
+ this, SLOT(slotSearchLeft(bool)));
+ QObject::connect(m_btnSearchRight, SIGNAL(toggled(bool)),
+ this, SLOT(slotSearchRight(bool)));
+ QObject::connect(m_btnStepLeft, SIGNAL(clicked()),
+ m_sldFrequency, SLOT(subtractStep()));
+ QObject::connect(m_btnStepRight, SIGNAL(clicked()),
+ m_sldFrequency, SLOT(addStep()));
+
+ // Tooltips
+
+ QToolTip::add(m_btnSearchLeft, i18n("Search for previous Radio Station"));
+ QToolTip::add(m_btnSearchRight, i18n("Search for next Radio Station"));
+ QToolTip::add(m_btnStepLeft, i18n("Decrement Frequency"));
+ QToolTip::add(m_btnStepRight, i18n("Increment Frequency"));
+ QToolTip::add(m_sldFrequency, i18n("Change Frequency"));
+
+ // Accelerators
+
+ QAccel *Accel = new QAccel (this);
+ Accel->insertItem (Key_Left, 100);
+ Accel->insertItem (Key_Right, 101);
+ Accel->connectItem (100, m_sldFrequency, SLOT(subtractStep()));
+ Accel->connectItem (101, m_sldFrequency, SLOT(addStep()));
+}
+
+
+RadioViewFrequencySeeker::~RadioViewFrequencySeeker()
+{
+}
+
+
+float RadioViewFrequencySeeker::getUsability (Interface *i) const
+{
+ if (dynamic_cast<IFrequencyRadio*>(i))
+ return 0.9;
+ else
+ return 0.0;
+}
+
+
+// Interface
+
+bool RadioViewFrequencySeeker::connectI (Interface *i)
+{
+ if (IFrequencyRadioClient::connectI(i)) {
+ ISeekRadioClient::connectI(i);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool RadioViewFrequencySeeker::disconnectI(Interface *i)
+{
+ bool a = IFrequencyRadioClient::disconnectI(i);
+ bool b = ISeekRadioClient::disconnectI(i);
+ return a || b;
+}
+
+
+
+// ISeekRadioClient
+
+bool RadioViewFrequencySeeker::noticeSeekStarted (bool up)
+{
+ m_ignoreChanges = true;
+ m_btnSearchLeft->setOn(!up);
+ m_btnSearchRight->setOn(up);
+ m_ignoreChanges = false;
+ return true;
+}
+
+
+bool RadioViewFrequencySeeker::noticeSeekStopped ()
+{
+ m_ignoreChanges = true;
+ m_btnSearchLeft->setOn(false);
+ m_btnSearchRight->setOn(false);
+ m_ignoreChanges = false;
+ return true;
+}
+
+
+bool RadioViewFrequencySeeker::noticeSeekFinished (const RadioStation &/*s*/, bool /*goodQuality*/)
+{
+ m_ignoreChanges = true;
+ m_btnSearchLeft->setOn(false);
+ m_btnSearchRight->setOn(false);
+ m_ignoreChanges = false;
+ return true;
+}
+
+
+
+// IFrequencyRadioClient
+
+bool RadioViewFrequencySeeker::noticeFrequencyChanged(float f, const RadioStation */*s*/)
+{
+ float step = queryScanStep();
+ if (step == 0) step = 0.000001;
+
+ m_ignoreChanges = true;
+ m_sldFrequency->setValue((int)rint(f / step));
+ m_ignoreChanges = false;
+ return true;
+}
+
+
+bool RadioViewFrequencySeeker::noticeMinMaxFrequencyChanged(float min, float max)
+{
+ float step = queryScanStep();
+ if (step == 0) step = 0.000001;
+
+ m_ignoreChanges = true;
+ m_sldFrequency->setMinValue((int)rint(min / step));
+ m_sldFrequency->setMaxValue((int)rint(max / step));
+ m_sldFrequency->setValue ((int)rint(queryFrequency() / step));
+ m_ignoreChanges = false;
+ return true;
+}
+
+
+bool RadioViewFrequencySeeker::noticeDeviceMinMaxFrequencyChanged(float /*min*/, float /*max*/)
+{
+ return false; // we don't care
+}
+
+
+bool RadioViewFrequencySeeker::noticeScanStepChanged(float s)
+{
+ if (s == 0) s = 0.000001;
+ m_ignoreChanges = true;
+ m_sldFrequency->setMinValue((int)rint(queryMinFrequency() / s));
+ m_sldFrequency->setMaxValue((int)rint(queryMaxFrequency() / s));
+ m_sldFrequency->setValue ((int)rint(queryFrequency() / s));
+ m_ignoreChanges = false;
+ return true;
+}
+
+
+void RadioViewFrequencySeeker::slotSearchLeft(bool on)
+{
+ if (m_ignoreChanges) return;
+ if (on) {
+ if (queryIsSeekUpRunning())
+ sendStopSeek();
+ if (!queryIsSeekRunning())
+ sendStartSeekDown();
+ } else {
+ if (queryIsSeekDownRunning())
+ sendStopSeek();
+ }
+ if (!queryIsSeekDownRunning())
+ m_btnSearchLeft->setOn(false);
+}
+
+
+void RadioViewFrequencySeeker::slotSearchRight(bool on)
+{
+ if (m_ignoreChanges) return;
+ if (on) {
+ if (queryIsSeekDownRunning())
+ sendStopSeek();
+ if (!queryIsSeekRunning())
+ sendStartSeekUp();
+ } else {
+ if (queryIsSeekUpRunning())
+ sendStopSeek();
+ }
+ if (!queryIsSeekUpRunning())
+ m_btnSearchRight->setOn(false);
+}
+
+
+void RadioViewFrequencySeeker::slotSliderChanged(int val)
+{
+ if (m_ignoreChanges) return;
+ sendFrequency(val * queryScanStep());
+}
+
+
+
+
+#include "radioview_frequencyseeker.moc"
diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.h b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.h
new file mode 100644
index 0000000..12ca7d4
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ radioview_frequencyseeker.h - description
+ -------------------
+ begin : Fre Jun 20 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIOVIEW_FREQUENCYSEEKER_H
+#define KRADIO_RADIOVIEW_FREQUENCYSEEKER_H
+
+#include "../../src/include/radiodevice_interfaces.h"
+#include "radioview_element.h"
+
+class QToolButton;
+class QSlider;
+
+class RadioViewFrequencySeeker : public RadioViewElement, // is a QObject, must be first
+ public ISeekRadioClient,
+ public IFrequencyRadioClient
+{
+Q_OBJECT
+public:
+ RadioViewFrequencySeeker(QWidget *parent, const QString &name);
+ ~RadioViewFrequencySeeker();
+
+ float getUsability(Interface *) const;
+
+// Interface
+
+ bool connectI (Interface *);
+ bool disconnectI(Interface *);
+
+// ISeekRadioClient
+RECEIVERS:
+ bool noticeSeekStarted (bool up);
+ bool noticeSeekStopped ();
+ bool noticeSeekFinished (const RadioStation &s, bool goodQuality);
+ bool noticeProgress (float ) { return false; }
+
+// IFrequencyRadioClient
+RECEIVERS:
+ bool noticeFrequencyChanged(float f, const RadioStation *s);
+ bool noticeMinMaxFrequencyChanged(float min, float max);
+ bool noticeDeviceMinMaxFrequencyChanged(float min, float max);
+ bool noticeScanStepChanged(float s);
+
+// own stuff ;)
+
+protected slots:
+
+ void slotSearchLeft(bool on);
+ void slotSearchRight(bool on);
+ void slotSliderChanged(int val);
+
+protected:
+
+ QToolButton *m_btnSearchLeft,
+ *m_btnStepLeft,
+ *m_btnStepRight,
+ *m_btnSearchRight;
+ QSlider *m_sldFrequency;
+
+ bool m_ignoreChanges;
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui
new file mode 100644
index 0000000..f4fc98c
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui
@@ -0,0 +1,167 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>RadioView_SeekerUI</class>
+<author>Ernst Martin Witte</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>RadioView_SeekerUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>477</width>
+ <height>43</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>RadioView_SeekInterface</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QToolButton" row="0" column="0">
+ <property name="name">
+ <cstring>btnSearchDown</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>TabFocus</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"2rightarrow"</iconset>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>search previous station</string>
+ </property>
+ </widget>
+ <widget class="QToolButton" row="0" column="1">
+ <property name="name">
+ <cstring>btnStepDown</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>TabFocus</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="autoRepeat">
+ <bool>true</bool>
+ </property>
+ <property name="iconSet">
+ <iconset>"2rightarrow"</iconset>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>decrease freq. by 0.05 MHz</string>
+ </property>
+ </widget>
+ <widget class="QSlider" row="0" column="2">
+ <property name="name">
+ <cstring>sldRange</cstring>
+ </property>
+ <property name="minValue">
+ <number>8700</number>
+ </property>
+ <property name="maxValue">
+ <number>10900</number>
+ </property>
+ <property name="lineStep">
+ <number>5</number>
+ </property>
+ <property name="pageStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>8700</number>
+ </property>
+ <property name="tracking">
+ <bool>true</bool>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="tickmarks">
+ <enum>NoMarks</enum>
+ </property>
+ <property name="tickInterval">
+ <number>100</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Frequency control</string>
+ <comment>Frequency</comment>
+ </property>
+ </widget>
+ <widget class="QToolButton" row="0" column="3">
+ <property name="name">
+ <cstring>btnStepUp</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>TabFocus</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="autoRepeat">
+ <bool>true</bool>
+ </property>
+ <property name="iconSet">
+ <iconset>"2rightarrow"</iconset>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>increase freq. by 0.05 MHz</string>
+ </property>
+ </widget>
+ <widget class="QToolButton" row="0" column="4">
+ <property name="name">
+ <cstring>btnSearchUp</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>TabFocus</enum>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"2rightarrow"</iconset>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>search next station</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>btnSearchDown</tabstop>
+ <tabstop>btnStepDown</tabstop>
+ <tabstop>sldRange</tabstop>
+ <tabstop>btnStepUp</tabstop>
+ <tabstop>btnSearchUp</tabstop>
+</tabstops>
+<includes>
+ <include location="local" impldecl="in implementation">radioview_seekinterface.ui.h</include>
+</includes>
+<functions>
+ <function access="protected">init()</function>
+ <function>destroy()</function>
+</functions>
+<pixmapfunction>SmallIconSet</pixmapfunction>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui.h b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui.h
new file mode 100644
index 0000000..1f75180
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui.h
@@ -0,0 +1,21 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+void RadioView_SeekerUI::init()
+{
+ Accel = new QAccel (this);
+ Accel->insertItem (Key_Left, 100);
+ Accel->insertItem (Key_Right, 101);
+ Accel->connectItem (100, sldRange, SLOT(subtractStep()));
+ Accel->connectItem (101, sldRange, SLOT(addStep()));
+}
+
+void RadioView_SeekerUI::destroy()
+{
+}
diff --git a/kradio3/plugins/gui-standard-display/radioview_volume.cpp b/kradio3/plugins/gui-standard-display/radioview_volume.cpp
new file mode 100644
index 0000000..d642aa4
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_volume.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+ radioview_volume.cpp - description
+ -------------------
+ begin : Don Jun 19 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 <math.h>
+#include <qslider.h>
+#include <qlayout.h>
+#include <qaccel.h>
+#include <qtooltip.h>
+
+#include <klocale.h>
+
+#include "radioview_volume.h"
+#include "../../src/include/plugins.h"
+
+#define SLIDER_MINVAL 0
+#define SLIDER_MAXVAL 32768
+#define SLIDER_RANGE (SLIDER_MAXVAL - SLIDER_MINVAL)
+
+RadioViewVolume::RadioViewVolume(QWidget *parent, const QString &name)
+ : RadioViewElement (parent, name, clsRadioSound),
+ m_slider(NULL),
+ m_handlingSlot(false)
+{
+ float v = 0;
+ SoundStreamID ssid = queryCurrentSoundStreamID();
+ sendLogDebug (QString ("RadioViewVolume: ssid=%1").arg(ssid.getID()));
+ queryPlaybackVolume(ssid, v);
+ m_slider = new QSlider(SLIDER_MINVAL,
+ SLIDER_MAXVAL,
+ SLIDER_RANGE/10,
+ getSlider4Volume(v),
+ Qt::Vertical, this);
+
+ QObject::connect(m_slider, SIGNAL(valueChanged(int)),
+ this, SLOT(slotVolumeChanged(int)));
+
+ QBoxLayout *l = new QBoxLayout(this, QBoxLayout::LeftToRight);
+ l->addWidget(m_slider);
+
+ // Tooltips
+
+ QToolTip::add(m_slider, i18n("Change Volume"));
+
+ // Accelerators
+ QAccel *Accel = new QAccel (this);
+ Accel->insertItem (Key_Up, 100);
+ Accel->insertItem (Key_Down, 101);
+ Accel->connectItem (100, m_slider, SLOT(subtractStep()));
+ Accel->connectItem (101, m_slider, SLOT(addStep()));
+
+}
+
+
+RadioViewVolume::~RadioViewVolume()
+{
+}
+
+
+float RadioViewVolume::getUsability (Interface */*i*/) const
+{
+ return 0.5; // there could be more features like mute control, capture settings, ...
+}
+
+
+bool RadioViewVolume::connectI (Interface *i)
+{
+ bool a = IRadioDeviceClient::connectI(i);
+ bool b = ISoundStreamClient::connectI(i);
+ return a || b;
+}
+
+
+bool RadioViewVolume::disconnectI(Interface *i)
+{
+ bool a = IRadioDeviceClient::disconnectI(i);
+ bool b = ISoundStreamClient::disconnectI(i);
+ return a || b;
+}
+
+void RadioViewVolume::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_notifyPlaybackVolumeChanged(this);
+ }
+}
+
+// ISoundStreamClient
+
+bool RadioViewVolume::noticePlaybackVolumeChanged(SoundStreamID id, float v)
+{
+ if (queryCurrentSoundStreamID() != id)
+ return false;
+ m_slider->setValue(getSlider4Volume(v));
+ return true;
+}
+
+
+
+void RadioViewVolume::slotVolumeChanged(int val)
+{
+ if (m_handlingSlot) return;
+ m_handlingSlot = true;
+ SoundStreamID ssid = queryCurrentSoundStreamID();
+ sendPlaybackVolume(ssid, getVolume4Slider(val));
+ m_handlingSlot = false;
+}
+
+
+int RadioViewVolume::getSlider4Volume(float volume)
+{
+ if (volume >= 1) volume = 1;
+ if (volume < 0) volume = 0;
+ return SLIDER_MAXVAL - (int)rint(SLIDER_RANGE * volume);
+}
+
+
+float RadioViewVolume::getVolume4Slider(int sl)
+{
+ if (sl > SLIDER_MAXVAL) sl = SLIDER_MAXVAL;
+ if (sl < SLIDER_MINVAL) sl = SLIDER_MINVAL;
+ return (float)(SLIDER_MAXVAL - sl) / (float)SLIDER_RANGE;
+}
+
+
+
+#include "radioview_volume.moc"
diff --git a/kradio3/plugins/gui-standard-display/radioview_volume.h b/kradio3/plugins/gui-standard-display/radioview_volume.h
new file mode 100644
index 0000000..a48c16d
--- /dev/null
+++ b/kradio3/plugins/gui-standard-display/radioview_volume.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ radioview_volume.h - description
+ -------------------
+ begin : Don Jun 19 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIOVIEW_VOLUME_H
+#define KRADIO_RADIOVIEW_VOLUME_H
+
+#include "../../src/include/radiodevice_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "radioview_element.h"
+
+/**
+ *@author Martin Witte
+ */
+
+class QSlider;
+
+class RadioViewVolume : public RadioViewElement, // is a QObject, must be first
+ public IRadioDeviceClient,
+ public ISoundStreamClient,
+ public IErrorLogClient
+{
+Q_OBJECT
+public:
+ RadioViewVolume(QWidget *parent, const QString &name);
+ ~RadioViewVolume();
+
+ float getUsability(Interface *) const;
+
+// Interface
+
+ bool connectI (Interface *);
+ bool disconnectI(Interface *);
+
+// IRadioDeviceClient
+RECEIVERS:
+ bool noticePowerChanged (bool /*on*/, const IRadioDevice */*sender*/) { return false; }
+ bool noticeStationChanged (const RadioStation &, const IRadioDevice */*sender*/) { return false; }
+ bool noticeDescriptionChanged (const QString &, const IRadioDevice */*sender*/) { return false; }
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/, const IRadioDevice */*sender*/) { return false; }
+
+// ISoundStreamClient
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+ bool noticePlaybackVolumeChanged(SoundStreamID id, float v);
+
+// own stuff
+protected slots:
+
+ void slotVolumeChanged(int val);
+
+protected:
+
+ int getSlider4Volume(float volume);
+ float getVolume4Slider(int sl);
+
+ QSlider *m_slider;
+ bool m_handlingSlot;
+
+};
+
+#endif
diff --git a/kradio3/plugins/lirc/Makefile.am b/kradio3/plugins/lirc/Makefile.am
new file mode 100644
index 0000000..383fe28
--- /dev/null
+++ b/kradio3/plugins/lirc/Makefile.am
@@ -0,0 +1,28 @@
+
+SUBDIRS = po .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = liblirc.la
+liblirc_la_SOURCES = lircsupport.cpp lirc-configuration-ui.ui \
+ lirc-configuration.cpp listviewitem_lirc.cpp
+liblirc_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+liblirc_la_LIBADD = $(LIB_LIRC)
+
+noinst_HEADERS = lircsupport.h lirc-configuration.h listviewitem_lirc.h
+
+
+install-data-local:
+ $(mkinstalldirs) "$(DESTDIR)$(kde_datadir)/kradio/"
+ $(INSTALL_DATA) "$(srcdir)/default-dot-lircrc" "$(DESTDIR)$(kde_datadir)/kradio/default-dot-lircrc"
+
+uninstall-local:
+ -rm -f "$(DESTDIR)$(kde_datadir)/kradio/default-dot-lircrc"
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-lirc.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-lirc.pot
diff --git a/kradio3/plugins/lirc/default-dot-lircrc b/kradio3/plugins/lirc/default-dot-lircrc
new file mode 100644
index 0000000..02ac704
--- /dev/null
+++ b/kradio3/plugins/lirc/default-dot-lircrc
@@ -0,0 +1,6 @@
+
+begin
+ prog = kradio
+ config = eventmap
+ repeat = 1
+end
diff --git a/kradio3/plugins/lirc/lirc-configuration-ui.ui b/kradio3/plugins/lirc/lirc-configuration-ui.ui
new file mode 100644
index 0000000..8fadc85
--- /dev/null
+++ b/kradio3/plugins/lirc/lirc-configuration-ui.ui
@@ -0,0 +1,110 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>LIRCConfigurationUI</class>
+<author>Ernst Martin Witte</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>LIRCConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>585</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>LIRCConfigurationUI</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView" row="0" column="0">
+ <column>
+ <property name="text">
+ <string>Action</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>LIRC String</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Alternative LIRC String</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_ActionList</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="itemMargin">
+ <number>2</number>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="Line" row="1" column="0">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>m_LabelHints</cstring>
+ </property>
+ <property name="text">
+ <string>textLabel1</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<pixmapfunction>SmallIconSet</pixmapfunction>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/lirc/lirc-configuration.cpp b/kradio3/plugins/lirc/lirc-configuration.cpp
new file mode 100644
index 0000000..9b98a44
--- /dev/null
+++ b/kradio3/plugins/lirc/lirc-configuration.cpp
@@ -0,0 +1,193 @@
+/***************************************************************************
+ lirc-configuration.cpp - description
+ -------------------
+ begin : Sat May 21 2005
+ copyright : (C) 2005 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 <klistview.h>
+#include <klocale.h>
+
+#include <qlistview.h>
+#include <qlabel.h>
+
+#include "lirc-configuration.h"
+#include "lircsupport.h"
+#include "listviewitem_lirc.h"
+
+LIRCConfiguration::LIRCConfiguration (QWidget *parent, LircSupport *dev)
+ : LIRCConfigurationUI(parent),
+ m_LIRC (dev),
+ m_dirty(true),
+ m_ignore_gui_updates(false)
+{
+ m_descriptions[LIRC_DIGIT_0] = i18n("digit 0");
+ m_descriptions[LIRC_DIGIT_1] = i18n("digit 1");
+ m_descriptions[LIRC_DIGIT_2] = i18n("digit 2");
+ m_descriptions[LIRC_DIGIT_3] = i18n("digit 3");
+ m_descriptions[LIRC_DIGIT_4] = i18n("digit 4");
+ m_descriptions[LIRC_DIGIT_5] = i18n("digit 5");
+ m_descriptions[LIRC_DIGIT_6] = i18n("digit 6");
+ m_descriptions[LIRC_DIGIT_7] = i18n("digit 7");
+ m_descriptions[LIRC_DIGIT_8] = i18n("digit 8");
+ m_descriptions[LIRC_DIGIT_9] = i18n("digit 9");
+ m_descriptions[LIRC_POWER_ON] = i18n("Power On");
+ m_descriptions[LIRC_POWER_OFF] = i18n("Power Off");
+ m_descriptions[LIRC_PAUSE] = i18n("Pause");
+ m_descriptions[LIRC_RECORD_START] = i18n("Start Recording");
+ m_descriptions[LIRC_RECORD_STOP] = i18n("Stop Recording");
+ m_descriptions[LIRC_VOLUME_INC] = i18n("Increase Volume");
+ m_descriptions[LIRC_VOLUME_DEC] = i18n("Decrease Volume");
+ m_descriptions[LIRC_CHANNEL_NEXT] = i18n("Next Channel");
+ m_descriptions[LIRC_CHANNEL_PREV] = i18n("Previous Channel");
+ m_descriptions[LIRC_SEARCH_NEXT] = i18n("Search Next Channel");
+ m_descriptions[LIRC_SEARCH_PREV] = i18n("Search Previous Channel");
+ m_descriptions[LIRC_SLEEP] = i18n("Enable Sleep Countdown");
+ m_descriptions[LIRC_APPLICATION_QUIT] = i18n("Quit KRadio");
+
+ int k = 0;
+ m_order[k++] = LIRC_DIGIT_0;
+ m_order[k++] = LIRC_DIGIT_1;
+ m_order[k++] = LIRC_DIGIT_2;
+ m_order[k++] = LIRC_DIGIT_3;
+ m_order[k++] = LIRC_DIGIT_4;
+ m_order[k++] = LIRC_DIGIT_5;
+ m_order[k++] = LIRC_DIGIT_6;
+ m_order[k++] = LIRC_DIGIT_7;
+ m_order[k++] = LIRC_DIGIT_8;
+ m_order[k++] = LIRC_DIGIT_9;
+ m_order[k++] = LIRC_POWER_ON;
+ m_order[k++] = LIRC_POWER_OFF;
+ m_order[k++] = LIRC_PAUSE;
+ m_order[k++] = LIRC_RECORD_START;
+ m_order[k++] = LIRC_RECORD_STOP;
+ m_order[k++] = LIRC_VOLUME_INC;
+ m_order[k++] = LIRC_VOLUME_DEC;
+ m_order[k++] = LIRC_CHANNEL_NEXT;
+ m_order[k++] = LIRC_CHANNEL_PREV;
+ m_order[k++] = LIRC_SEARCH_NEXT;
+ m_order[k++] = LIRC_SEARCH_PREV;
+ m_order[k++] = LIRC_SLEEP;
+ m_order[k++] = LIRC_APPLICATION_QUIT;
+
+ m_ActionList->setSorting(-1);
+ m_ActionList->setColumnWidthMode(0, QListView::Maximum);
+ m_ActionList->setColumnWidthMode(1, QListView::Maximum);
+ m_ActionList->setColumnWidthMode(2, QListView::Maximum);
+
+ connect(m_ActionList, SIGNAL(itemRenamed(QListViewItem*, int)), this, SLOT(slotSetDirty()));
+ slotCancel();
+}
+
+
+LIRCConfiguration::~LIRCConfiguration ()
+{
+}
+
+
+void LIRCConfiguration::slotOK()
+{
+ if (m_dirty && m_LIRC) {
+ QListViewItem *item = m_ActionList->firstChild();
+
+ QMap<LIRC_Actions, QString> actions;
+ QMap<LIRC_Actions, QString> alt_actions;
+
+ for (int i = 0; item; ++i, item = item->nextSibling()) {
+ LIRC_Actions action = m_order[i];
+ actions[action] = item->text(1);
+ alt_actions[action] = item->text(2);
+ }
+ m_LIRC->setActions(actions, alt_actions);
+ }
+ m_dirty = false;
+}
+
+
+void LIRCConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ m_ignore_gui_updates = true;
+ m_ActionList->clear();
+ if (m_LIRC) {
+ const QMap<LIRC_Actions, QString> &actions = m_LIRC->getActions();
+ const QMap<LIRC_Actions, QString> &alt_actions = m_LIRC->getAlternativeActions();
+
+ for (unsigned i = 0; m_order.contains(i) && i < m_order.count(); ++i) {
+ LIRC_Actions action = m_order[i];
+ addKey(m_descriptions[action], actions[action], alt_actions[action]);
+ }
+ }
+
+ slotRenamingStopped(NULL, -1);
+ m_ignore_gui_updates = false;
+ }
+ m_dirty = false;
+}
+
+
+void LIRCConfiguration::addKey(const QString &descr, const QString &key, const QString &alt_key)
+{
+ ListViewItemLirc *item = new ListViewItemLirc(m_ActionList, m_ActionList->lastChild());
+ if (item) {
+ QObject::connect(item, SIGNAL(sigRenamingStarted (ListViewItemLirc *, int)),
+ this, SLOT (slotRenamingStarted(ListViewItemLirc *, int)));
+ QObject::connect(item, SIGNAL(sigRenamingStopped (ListViewItemLirc *, int)),
+ this, SLOT (slotRenamingStopped(ListViewItemLirc *, int)));
+ item->setText(0, descr);
+ item->setText(1, key);
+ item->setText(2, alt_key);
+ item->setRenameEnabled(1, true);
+ item->setRenameEnabled(2, true);
+ }
+}
+
+void LIRCConfiguration::slotUpdateConfig()
+{
+ slotSetDirty();
+ slotCancel();
+}
+
+void LIRCConfiguration::slotRawLIRCSignal(const QString &val, int /*repeat_counter*/, bool &consumed)
+{
+ QListViewItem *_it = m_ActionList->currentItem();
+ ListViewItemLirc *it = static_cast<ListViewItemLirc*>(_it);
+ if (it->isRenamingInProcess()) {
+ int col = it->getRenamingColumn();
+ it->cancelRename(col);
+ it->setText(col, val);
+ consumed = true;
+ m_dirty = true;
+ }
+}
+
+void LIRCConfiguration::slotRenamingStarted(ListViewItemLirc */*sender*/, int /*col*/)
+{
+ m_LabelHints->setText(i18n("Enter the key string of your remote or just press the button on your remote control"));
+}
+
+
+void LIRCConfiguration::slotRenamingStopped(ListViewItemLirc */*sender*/, int /*col*/)
+{
+ m_LabelHints->setText(i18n("Double Click on the entries to change the assignments"));
+}
+
+
+void LIRCConfiguration::slotSetDirty()
+{
+ if (!m_ignore_gui_updates) {
+ m_dirty = true;
+ }
+}
+
+#include "lirc-configuration.moc"
diff --git a/kradio3/plugins/lirc/lirc-configuration.h b/kradio3/plugins/lirc/lirc-configuration.h
new file mode 100644
index 0000000..13bcda4
--- /dev/null
+++ b/kradio3/plugins/lirc/lirc-configuration.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ lirc-configuration.h - description
+ -------------------
+ begin : Sat May 21 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_LIRC_CONFIGURATION_H
+#define KRADIO_LIRC_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "lirc-configuration-ui.h"
+#include "lircsupport.h"
+#include "listviewitem_lirc.h"
+
+class LIRCConfiguration : public LIRCConfigurationUI
+{
+Q_OBJECT
+public :
+ LIRCConfiguration (QWidget *parent, LircSupport *);
+ ~LIRCConfiguration ();
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+ void slotUpdateConfig();
+ void slotRawLIRCSignal(const QString &val, int repeat_counter, bool &consumed);
+
+ void slotRenamingStarted(ListViewItemLirc *, int);
+ void slotRenamingStopped(ListViewItemLirc *, int);
+
+protected:
+ void addKey(const QString &descr, const QString &key, const QString &alt_key);
+
+ LircSupport *m_LIRC;
+
+ QMap<int, LIRC_Actions> m_order;
+ QMap<LIRC_Actions, QString> m_descriptions;
+
+ bool m_dirty;
+ bool m_ignore_gui_updates;
+};
+
+#endif
diff --git a/kradio3/plugins/lirc/lircsupport.cpp b/kradio3/plugins/lirc/lircsupport.cpp
new file mode 100644
index 0000000..3b64580
--- /dev/null
+++ b/kradio3/plugins/lirc/lircsupport.cpp
@@ -0,0 +1,553 @@
+/***************************************************************************
+ lircsupport.cpp - description
+ -------------------
+ begin : Mon Feb 4 2002
+ copyright : (C) 2002 by Martin Witte / Frank Schwanz
+ email : witte@kawo1.rwth-aachen.de / schwanz@fh-brandenburg.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 "lircsupport.h"
+
+#ifdef HAVE_LIRC
+#include <lirc/lirc_client.h>
+#endif
+
+#include <qsocketnotifier.h>
+#include <qtimer.h>
+#include <qfile.h>
+
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kstandarddirs.h>
+
+#include "../../src/include/errorlog-interfaces.h"
+#include "../../src/include/radiodevice_interfaces.h"
+#include "../../src/include/stationlist.h"
+#include "../../src/include/aboutwidget.h"
+
+#include "lirc-configuration.h"
+
+#include <cstdlib>
+
+#define LIRCRC ".lircrc"
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+//#ifdef HAVE_LIRC
+PLUGIN_LIBRARY_FUNCTIONS(LircSupport, "kradio-lirc", i18n("Linux Infrared Control (LIRC) Support"));
+//#endif
+
+/////////////////////////////////////////////////////////////////////////////
+
+LircSupport::LircSupport(const QString &name)
+ : PluginBase(name, i18n("LIRC Plugin")),
+ m_TakeRawLIRC(false)
+{
+
+#ifdef HAVE_LIRC
+ logDebug(i18n("initializing kradio lirc plugin"));
+ fprintf (stderr, "%s\n", (const char*)i18n("initializing kradio lirc plugin").utf8());
+ char *prg = (char*)"kradio";
+
+ QString slircrc = getenv("HOME");
+ slircrc += "/" LIRCRC;
+
+ QFile lircrc(slircrc);
+ if (!lircrc.exists()) {
+ logWarning(i18n("%1 does not exist. File was created with KRadio's default .lircrc proposal").arg(LIRCRC));
+ QFile default_lircrc(locate("data", "kradio/default-dot-lircrc"));
+ lircrc.open(IO_WriteOnly);
+ default_lircrc.open(IO_ReadOnly);
+ char *buf = new char [default_lircrc.size() + 1];
+ default_lircrc.readBlock(buf, default_lircrc.size());
+ lircrc.writeBlock(buf, default_lircrc.size());
+ lircrc.close();
+ default_lircrc.close();
+ delete buf;
+ }
+
+ m_fd_lirc = lirc_init(prg, 1);
+ m_lirc_notify = 0;
+ m_lircConfig = 0;
+
+ if (m_fd_lirc != -1) {
+ if (lirc_readconfig (NULL, &m_lircConfig, NULL) == 0) {
+ m_lirc_notify = new QSocketNotifier(m_fd_lirc, QSocketNotifier::Read, this, "lirc_notifier");
+ if (m_lirc_notify)
+ QObject::connect(m_lirc_notify, SIGNAL(activated(int)), this, SLOT(slotLIRC(int)));
+
+ // check config
+ lirc_config_entry *found = NULL;
+ for (lirc_config_entry *e = m_lircConfig->first; e; e = e->next) {
+ if (QString(e->prog) == prg)
+ found = e;
+ }
+ if (!found) {
+ logWarning(i18n("There is no entry for kradio in any of your .lircrc files."));
+ logWarning(i18n("Please setup your .lircrc files correctly."));
+ m_TakeRawLIRC = true;
+ }
+
+ } else {
+ lirc_deinit();
+ m_fd_lirc = -1;
+ }
+ }
+
+ if (m_fd_lirc == -1) {
+ logWarning(i18n("Initializing kradio lirc plugin failed"));
+ fprintf (stderr, "%s\n", (const char*)i18n("Initializing kradio lirc plugin failed").utf8());
+ } else {
+ logDebug(i18n("Initializing kradio lirc plugin successful"));
+ fprintf (stderr, "%s\n", (const char*)i18n("Initializing kradio lirc plugin successful").utf8());
+ }
+#endif
+
+ m_kbdTimer = new QTimer (this);
+ QObject::connect (m_kbdTimer, SIGNAL(timeout()), this, SLOT(slotKbdTimedOut()));
+
+ m_addIndex = 0;
+}
+
+
+LircSupport::~LircSupport()
+{
+#ifdef HAVE_LIRC
+ if (m_fd_lirc != -1)
+ lirc_deinit();
+ if (m_lircConfig)
+ lirc_freeconfig(m_lircConfig);
+ m_fd_lirc = -1;
+ m_lircConfig = 0;
+#endif
+}
+
+
+void LircSupport::slotLIRC(int /*socket*/ )
+{
+#ifdef HAVE_LIRC
+ if (!m_lircConfig || !m_lirc_notify || m_fd_lirc == -1)
+ return;
+
+ char *code = 0, *c = 0;
+ if (lirc_nextcode(&code) == 0) {
+ while(m_TakeRawLIRC || (lirc_code2char (m_lircConfig, code, &c) == 0 && c != NULL)) {
+
+ QString x = c;
+ int repeat_counter = 1;
+ if (m_TakeRawLIRC || (QString(c) == "eventmap")) {
+ QStringList l = QStringList::split(" ", code);
+ if (l.count() >=4) {
+ x = l[2];
+ repeat_counter = l[1].toInt(NULL, 16);
+ }
+ }
+
+ bool consumed = false;
+ logDebug(QString("LIRC: ") + x);
+
+ emit sigRawLIRCSignal(x, repeat_counter, consumed);
+
+ if (!consumed) {
+ if (!checkActions(x, repeat_counter, m_Actions))
+ checkActions(x, repeat_counter, m_AlternativeActions);
+ }
+ }
+ }
+ else {
+ // some error has occurred on the socket => close lirc plugin
+ logWarning(i18n("Reading from LIRC socket failed. Disabling LIRC Functions till next start of kradio"));
+ delete m_lirc_notify;
+ m_lirc_notify = NULL;
+ }
+
+ if (code)
+ free (code);
+#endif
+}
+
+
+void LircSupport::slotKbdTimedOut()
+{
+ activateStation (m_addIndex);
+ m_addIndex = 0;
+}
+
+
+void LircSupport::activateStation (int i)
+{
+ if (! sendActivateStation(i - 1))
+ sendActivateStation( (i + 9) % 10);
+}
+
+
+bool LircSupport::connectI (Interface *i)
+{
+ bool a = IRadioClient::connectI (i);
+ bool b = ITimeControlClient::connectI (i);
+ bool c = IRadioDevicePoolClient::connectI (i);
+ bool d = PluginBase::connectI(i);
+ bool e = ISoundStreamClient::connectI(i);
+ return a || b || c || d || e;
+}
+
+
+bool LircSupport::disconnectI (Interface *i)
+{
+ bool a = IRadioClient::disconnectI (i);
+ bool b = ITimeControlClient::disconnectI (i);
+ bool c = IRadioDevicePoolClient::disconnectI (i);
+ bool d = PluginBase::disconnectI(i);
+ bool e = ISoundStreamClient::disconnectI(i);
+ return a || b || c || d || e;
+}
+
+
+
+void LircSupport::saveState (KConfig *c) const
+{
+ c->writeEntry("LIRC_DIGIT_0", m_Actions[LIRC_DIGIT_0]);
+ c->writeEntry("LIRC_DIGIT_1", m_Actions[LIRC_DIGIT_1]);
+ c->writeEntry("LIRC_DIGIT_2", m_Actions[LIRC_DIGIT_2]);
+ c->writeEntry("LIRC_DIGIT_3", m_Actions[LIRC_DIGIT_3]);
+ c->writeEntry("LIRC_DIGIT_4", m_Actions[LIRC_DIGIT_4]);
+ c->writeEntry("LIRC_DIGIT_5", m_Actions[LIRC_DIGIT_5]);
+ c->writeEntry("LIRC_DIGIT_6", m_Actions[LIRC_DIGIT_6]);
+ c->writeEntry("LIRC_DIGIT_7", m_Actions[LIRC_DIGIT_7]);
+ c->writeEntry("LIRC_DIGIT_8", m_Actions[LIRC_DIGIT_8]);
+ c->writeEntry("LIRC_DIGIT_9", m_Actions[LIRC_DIGIT_9]);
+ c->writeEntry("LIRC_POWER_ON", m_Actions[LIRC_POWER_ON]);
+ c->writeEntry("LIRC_POWER_OFF", m_Actions[LIRC_POWER_OFF]);
+ c->writeEntry("LIRC_PAUSE", m_Actions[LIRC_PAUSE]);
+ c->writeEntry("LIRC_RECORD_START", m_Actions[LIRC_RECORD_START]);
+ c->writeEntry("LIRC_RECORD_STOP", m_Actions[LIRC_RECORD_STOP]);
+ c->writeEntry("LIRC_VOLUME_INC", m_Actions[LIRC_VOLUME_INC]);
+ c->writeEntry("LIRC_VOLUME_DEC", m_Actions[LIRC_VOLUME_DEC]);
+ c->writeEntry("LIRC_CHANNEL_NEXT", m_Actions[LIRC_CHANNEL_NEXT]);
+ c->writeEntry("LIRC_CHANNEL_PREV", m_Actions[LIRC_CHANNEL_PREV]);
+ c->writeEntry("LIRC_SEARCH_NEXT", m_Actions[LIRC_SEARCH_NEXT]);
+ c->writeEntry("LIRC_SEARCH_PREV", m_Actions[LIRC_SEARCH_PREV]);
+ c->writeEntry("LIRC_SLEEP", m_Actions[LIRC_SLEEP]);
+ c->writeEntry("LIRC_APPLICATION_QUIT", m_Actions[LIRC_APPLICATION_QUIT]);
+
+
+ c->writeEntry("ALT_LIRC_DIGIT_0", m_AlternativeActions[LIRC_DIGIT_0]);
+ c->writeEntry("ALT_LIRC_DIGIT_1", m_AlternativeActions[LIRC_DIGIT_1]);
+ c->writeEntry("ALT_LIRC_DIGIT_2", m_AlternativeActions[LIRC_DIGIT_2]);
+ c->writeEntry("ALT_LIRC_DIGIT_3", m_AlternativeActions[LIRC_DIGIT_3]);
+ c->writeEntry("ALT_LIRC_DIGIT_4", m_AlternativeActions[LIRC_DIGIT_4]);
+ c->writeEntry("ALT_LIRC_DIGIT_5", m_AlternativeActions[LIRC_DIGIT_5]);
+ c->writeEntry("ALT_LIRC_DIGIT_6", m_AlternativeActions[LIRC_DIGIT_6]);
+ c->writeEntry("ALT_LIRC_DIGIT_7", m_AlternativeActions[LIRC_DIGIT_7]);
+ c->writeEntry("ALT_LIRC_DIGIT_8", m_AlternativeActions[LIRC_DIGIT_8]);
+ c->writeEntry("ALT_LIRC_DIGIT_9", m_AlternativeActions[LIRC_DIGIT_9]);
+ c->writeEntry("ALT_LIRC_POWER_ON", m_AlternativeActions[LIRC_POWER_ON]);
+ c->writeEntry("ALT_LIRC_POWER_OFF", m_AlternativeActions[LIRC_POWER_OFF]);
+ c->writeEntry("ALT_LIRC_PAUSE", m_AlternativeActions[LIRC_PAUSE]);
+ c->writeEntry("ALT_LIRC_RECORD_START", m_AlternativeActions[LIRC_RECORD_START]);
+ c->writeEntry("ALT_LIRC_RECORD_STOP", m_AlternativeActions[LIRC_RECORD_STOP]);
+ c->writeEntry("ALT_LIRC_VOLUME_INC", m_AlternativeActions[LIRC_VOLUME_INC]);
+ c->writeEntry("ALT_LIRC_VOLUME_DEC", m_AlternativeActions[LIRC_VOLUME_DEC]);
+ c->writeEntry("ALT_LIRC_CHANNEL_NEXT", m_AlternativeActions[LIRC_CHANNEL_NEXT]);
+ c->writeEntry("ALT_LIRC_CHANNEL_PREV", m_AlternativeActions[LIRC_CHANNEL_PREV]);
+ c->writeEntry("ALT_LIRC_SEARCH_NEXT", m_AlternativeActions[LIRC_SEARCH_NEXT]);
+ c->writeEntry("ALT_LIRC_SEARCH_PREV", m_AlternativeActions[LIRC_SEARCH_PREV]);
+ c->writeEntry("ALT_LIRC_SLEEP", m_AlternativeActions[LIRC_SLEEP]);
+ c->writeEntry("ALT_LIRC_APPLICATION_QUIT", m_AlternativeActions[LIRC_APPLICATION_QUIT]);
+}
+
+void LircSupport::restoreState (KConfig *c)
+{
+ m_Actions[LIRC_DIGIT_0] = c->readEntry("LIRC_DIGIT_0", "0");
+ m_Actions[LIRC_DIGIT_1] = c->readEntry("LIRC_DIGIT_1", "1");
+ m_Actions[LIRC_DIGIT_2] = c->readEntry("LIRC_DIGIT_2", "2");
+ m_Actions[LIRC_DIGIT_3] = c->readEntry("LIRC_DIGIT_3", "3");
+ m_Actions[LIRC_DIGIT_4] = c->readEntry("LIRC_DIGIT_4", "4");
+ m_Actions[LIRC_DIGIT_5] = c->readEntry("LIRC_DIGIT_5", "5");
+ m_Actions[LIRC_DIGIT_6] = c->readEntry("LIRC_DIGIT_6", "6");
+ m_Actions[LIRC_DIGIT_7] = c->readEntry("LIRC_DIGIT_7", "7");
+ m_Actions[LIRC_DIGIT_8] = c->readEntry("LIRC_DIGIT_8", "8");
+ m_Actions[LIRC_DIGIT_9] = c->readEntry("LIRC_DIGIT_9", "9");
+ m_Actions[LIRC_POWER_ON] = c->readEntry("LIRC_POWER_ON", "RADIO");
+ m_Actions[LIRC_POWER_OFF] = c->readEntry("LIRC_POWER_OFF", "RADIO");
+ m_Actions[LIRC_PAUSE] = c->readEntry("LIRC_PAUSE", "FULL_SCREEN");
+ m_Actions[LIRC_RECORD_START] = c->readEntry("LIRC_RECORD_START", "");
+ m_Actions[LIRC_RECORD_STOP] = c->readEntry("LIRC_RECORD_STOP", "");
+ m_Actions[LIRC_VOLUME_INC] = c->readEntry("LIRC_VOLUME_INC", "VOL+");
+ m_Actions[LIRC_VOLUME_DEC] = c->readEntry("LIRC_VOLUME_DEC", "VOL-");
+ m_Actions[LIRC_CHANNEL_NEXT] = c->readEntry("LIRC_CHANNEL_NEXT", "CH+");
+ m_Actions[LIRC_CHANNEL_PREV] = c->readEntry("LIRC_CHANNEL_PREV", "CH-");
+ m_Actions[LIRC_SEARCH_NEXT] = c->readEntry("LIRC_SEARCH_NEXT", "SOURCE");
+ m_Actions[LIRC_SEARCH_PREV] = c->readEntry("LIRC_SEARCH_PREV", "MUTE");
+ m_Actions[LIRC_SLEEP] = c->readEntry("LIRC_SLEEP", "MINIMIZE");
+ m_Actions[LIRC_APPLICATION_QUIT] = c->readEntry("LIRC_APPLICATION_QUIT", "");
+
+
+ m_AlternativeActions[LIRC_DIGIT_0] = c->readEntry("ALT_LIRC_DIGIT_0", "");
+ m_AlternativeActions[LIRC_DIGIT_1] = c->readEntry("ALT_LIRC_DIGIT_1", "");
+ m_AlternativeActions[LIRC_DIGIT_2] = c->readEntry("ALT_LIRC_DIGIT_2", "");
+ m_AlternativeActions[LIRC_DIGIT_3] = c->readEntry("ALT_LIRC_DIGIT_3", "");
+ m_AlternativeActions[LIRC_DIGIT_4] = c->readEntry("ALT_LIRC_DIGIT_4", "");
+ m_AlternativeActions[LIRC_DIGIT_5] = c->readEntry("ALT_LIRC_DIGIT_5", "");
+ m_AlternativeActions[LIRC_DIGIT_6] = c->readEntry("ALT_LIRC_DIGIT_6", "");
+ m_AlternativeActions[LIRC_DIGIT_7] = c->readEntry("ALT_LIRC_DIGIT_7", "");
+ m_AlternativeActions[LIRC_DIGIT_8] = c->readEntry("ALT_LIRC_DIGIT_8", "");
+ m_AlternativeActions[LIRC_DIGIT_9] = c->readEntry("ALT_LIRC_DIGIT_9", "");
+ m_AlternativeActions[LIRC_POWER_ON] = c->readEntry("ALT_LIRC_POWER_ON", "");
+ m_AlternativeActions[LIRC_POWER_OFF] = c->readEntry("ALT_LIRC_POWER_OFF", "TV");
+ m_AlternativeActions[LIRC_PAUSE] = c->readEntry("ALT_LIRC_PAUSE", "");
+ m_AlternativeActions[LIRC_RECORD_START] = c->readEntry("ALT_LIRC_RECORD_START", "");
+ m_AlternativeActions[LIRC_RECORD_STOP] = c->readEntry("ALT_LIRC_RECORD_STOP", "");
+ m_AlternativeActions[LIRC_VOLUME_INC] = c->readEntry("ALT_LIRC_VOLUME_INC", "");
+ m_AlternativeActions[LIRC_VOLUME_DEC] = c->readEntry("ALT_LIRC_VOLUME_DEC", "");
+ m_AlternativeActions[LIRC_CHANNEL_NEXT] = c->readEntry("ALT_LIRC_CHANNEL_NEXT", "");
+ m_AlternativeActions[LIRC_CHANNEL_PREV] = c->readEntry("ALT_LIRC_CHANNEL_PREV", "");
+ m_AlternativeActions[LIRC_SEARCH_NEXT] = c->readEntry("ALT_LIRC_SEARCH_NEXT", "");
+ m_AlternativeActions[LIRC_SEARCH_PREV] = c->readEntry("ALT_LIRC_SEARCH_PREV", "");
+ m_AlternativeActions[LIRC_SLEEP] = c->readEntry("ALT_LIRC_SLEEP", "");
+ m_AlternativeActions[LIRC_APPLICATION_QUIT] = c->readEntry("ALT_LIRC_APPLICATION_QUIT", "");
+
+ emit sigUpdateConfig();
+}
+
+
+ConfigPageInfo LircSupport::createConfigurationPage()
+{
+ LIRCConfiguration *conf = new LIRCConfiguration(NULL, this);
+ QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig()));
+ QObject::connect(this, SIGNAL(sigRawLIRCSignal(const QString &, int, bool &)),
+ conf, SLOT (slotRawLIRCSignal(const QString &, int, bool &)));
+ return ConfigPageInfo (conf,
+ i18n("LIRC Support"),
+ i18n("LIRC Plugin"),
+ "connect_creating");
+}
+
+
+AboutPageInfo LircSupport::createAboutPage()
+{
+/* KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("Linux Infrared Remote Control Support for KRadio"),
+ KAboutData::License_GPL,
+ "(c) 2002-2005 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/kradio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed),
+ i18n("LIRC Support"),
+ i18n("LIRC Plugin"),
+ "connect_creating"
+ );*/
+ return AboutPageInfo();
+}
+
+
+bool LircSupport::checkActions(const QString &lirc_string, int repeat_counter, const QMap<LIRC_Actions, QString> &map)
+{
+ SoundStreamID streamID = queryCurrentSoundStreamID();
+
+ bool retval = false;
+ bool q = false;
+ SoundFormat sf;
+ ISeekRadio *seeker = NULL;
+
+ QMapConstIterator<LIRC_Actions, QString> it = map.begin();
+ QMapConstIterator<LIRC_Actions, QString> end = map.end();
+ for (; !retval && it != end; ++it) {
+ if ((*it).length() && lirc_string == *it) {
+ LIRC_Actions action = it.key();
+ int digit = -1;
+ switch (action) {
+ case LIRC_DIGIT_0 :
+ if (repeat_counter == 0) {
+ digit = 0;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_1 :
+ if (repeat_counter == 0) {
+ digit = 1;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_2 :
+ if (repeat_counter == 0) {
+ digit = 2;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_3 :
+ if (repeat_counter == 0) {
+ digit = 3;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_4 :
+ if (repeat_counter == 0) {
+ digit = 4;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_5 :
+ if (repeat_counter == 0) {
+ digit = 5;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_6 :
+ if (repeat_counter == 0) {
+ digit = 6;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_7 :
+ if (repeat_counter == 0) {
+ digit = 7;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_8 :
+ if (repeat_counter == 0) {
+ digit = 8;
+ retval = true;
+ }
+ break;
+ case LIRC_DIGIT_9 :
+ if (repeat_counter == 0) {
+ digit = 9;
+ retval = true;
+ }
+ break;
+ case LIRC_POWER_ON :
+ if (repeat_counter == 0 && !queryIsPowerOn()) {
+ retval = true;
+ sendPowerOn();
+ }
+ break;
+ case LIRC_POWER_OFF :
+ if (repeat_counter == 0 && queryIsPowerOn()) {
+ retval = true;
+ sendPowerOff();
+ }
+ break;
+ case LIRC_PAUSE :
+ if (repeat_counter == 0 && queryIsPowerOn()) {
+ retval = true;
+ sendPausePlayback(streamID);
+ }
+ break;
+ case LIRC_RECORD_START :
+ queryIsRecordingRunning(streamID, q = false, sf);
+ if (repeat_counter == 0 && !q) {
+ retval = true;
+ sendStartRecording(streamID);
+ }
+ break;
+ case LIRC_RECORD_STOP :
+ queryIsRecordingRunning(streamID, q = false, sf);
+ if (repeat_counter == 0 && q) {
+ retval = true;
+ sendStopRecording(streamID);
+ }
+ break;
+ case LIRC_VOLUME_INC :
+ if (queryIsPowerOn()) {
+ retval = true;
+ float oldVolume = 0;
+ queryPlaybackVolume(streamID, oldVolume);
+ sendPlaybackVolume (streamID, oldVolume + 1.0/32.0);
+ }
+ break;
+ case LIRC_VOLUME_DEC :
+ if (queryIsPowerOn()) {
+ retval = true;
+ float oldVolume = 0;
+ queryPlaybackVolume(streamID, oldVolume);
+ sendPlaybackVolume (streamID, oldVolume - 1.0/32.0);
+ }
+ break;
+ case LIRC_CHANNEL_NEXT :
+ if (repeat_counter == 0 && queryIsPowerOn()) {
+ retval = true;
+ int k = queryCurrentStationIdx() + 1;
+ if (k >= queryStations().count())
+ k = 0;
+ sendActivateStation(k);
+ }
+ break;
+ case LIRC_CHANNEL_PREV :
+ if (repeat_counter == 0 && queryIsPowerOn()) {
+ retval = true;
+ int k = queryCurrentStationIdx() - 1;
+ if (k < 0)
+ k = queryStations().count() - 1;
+ sendActivateStation(k);
+ }
+ break;
+ case LIRC_SEARCH_NEXT :
+ if (repeat_counter == 0 && queryIsPowerOn()) {
+ retval = true;
+ seeker = dynamic_cast<ISeekRadio*> (queryActiveDevice());
+ seeker->startSeekUp();
+ }
+ break;
+ case LIRC_SEARCH_PREV :
+ if (repeat_counter == 0 && queryIsPowerOn()) {
+ retval = true;
+ seeker = dynamic_cast<ISeekRadio*> (queryActiveDevice());
+ seeker->startSeekDown();
+ }
+ break;
+ case LIRC_SLEEP :
+ if (repeat_counter == 0 && queryIsPowerOn()) {
+ retval = true;
+ sendStartCountdown();
+ }
+ break;
+ case LIRC_APPLICATION_QUIT :
+ retval = true;
+ kapp->quit();
+ break;
+ default:
+ break;
+ }
+
+ if (digit >= 0) {
+ if (m_addIndex || digit == 0) {
+ activateStation(m_addIndex * 10 + digit);
+ m_kbdTimer->stop();
+ m_addIndex = 0;
+ } else {
+ m_addIndex = digit;
+ m_kbdTimer->start(500, true);
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+
+void LircSupport::setActions(const QMap<LIRC_Actions, QString> &actions, const QMap<LIRC_Actions, QString> &alt_actions)
+{
+ m_Actions = actions;
+ m_AlternativeActions = alt_actions;
+}
+
+
+#include "lircsupport.moc"
diff --git a/kradio3/plugins/lirc/lircsupport.h b/kradio3/plugins/lirc/lircsupport.h
new file mode 100644
index 0000000..47a113f
--- /dev/null
+++ b/kradio3/plugins/lirc/lircsupport.h
@@ -0,0 +1,159 @@
+/***************************************************************************
+ lircsupport.h - description
+ -------------------
+ begin : Mon Feb 4 2002
+ copyright : (C) 2002 by Martin Witte / Frank Schwanz
+ email : witte@kawo1.rwth-aachen.de / schwanz@fh-brandenburg.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef LIRCSUPPORT_H
+#define LIRCSUPPORT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qobject.h>
+#include "../../src/include/timecontrol_interfaces.h"
+#include "../../src/include/radio_interfaces.h"
+#include "../../src/include/radiodevicepool_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "../../src/include/plugins.h"
+
+
+enum LIRC_Actions {
+ LIRC_DIGIT_0,
+ LIRC_DIGIT_1,
+ LIRC_DIGIT_2,
+ LIRC_DIGIT_3,
+ LIRC_DIGIT_4,
+ LIRC_DIGIT_5,
+ LIRC_DIGIT_6,
+ LIRC_DIGIT_7,
+ LIRC_DIGIT_8,
+ LIRC_DIGIT_9,
+ LIRC_POWER_ON,
+ LIRC_POWER_OFF,
+ LIRC_PAUSE,
+ LIRC_RECORD_START,
+ LIRC_RECORD_STOP,
+ LIRC_VOLUME_INC,
+ LIRC_VOLUME_DEC,
+ LIRC_CHANNEL_NEXT,
+ LIRC_CHANNEL_PREV,
+ LIRC_SEARCH_NEXT,
+ LIRC_SEARCH_PREV,
+ LIRC_SLEEP,
+ LIRC_APPLICATION_QUIT
+};
+
+
+struct lirc_config;
+class QSocketNotifier;
+class QTimer;
+
+class LircSupport : public QObject,
+ public PluginBase,
+ public IRadioClient,
+ public ITimeControlClient,
+ public ISoundStreamClient,
+ public IRadioDevicePoolClient
+{
+Q_OBJECT
+public:
+ LircSupport(const QString &name);
+ ~LircSupport();
+
+ virtual bool connectI (Interface *);
+ virtual bool disconnectI (Interface *);
+
+ virtual QString pluginClassName() const { return "LircSupport"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+
+ virtual void setActions(const QMap<LIRC_Actions, QString> &actions, const QMap<LIRC_Actions, QString> &alt_actions);
+ virtual const QMap<LIRC_Actions, QString> &getActions() const { return m_Actions; }
+ virtual const QMap<LIRC_Actions, QString> &getAlternativeActions() const { return m_AlternativeActions; }
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // IRadioClient methods
+
+RECEIVERS:
+ bool noticePowerChanged(bool /*on*/) { return false; }
+ bool noticeStationChanged (const RadioStation &, int /*idx*/) { return false; }
+ bool noticeStationsChanged(const StationList &/*sl*/) { return false; }
+ bool noticePresetFileChanged(const QString &/*f*/) { return false; }
+
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; }
+
+ // ITimeControlClient
+
+RECEIVERS:
+ bool noticeAlarmsChanged(const AlarmVector &) { return false; }
+ bool noticeAlarm(const Alarm &) { return false; }
+ bool noticeNextAlarmChanged(const Alarm *) { return false; }
+ bool noticeCountdownStarted(const QDateTime &/*end*/) { return false; }
+ bool noticeCountdownStopped() { return false; }
+ bool noticeCountdownZero() { return false; }
+ bool noticeCountdownSecondsChanged(int /*n*/) { return false; }
+
+ // IRadioDevicePoolClient
+
+RECEIVERS:
+ bool noticeActiveDeviceChanged(IRadioDevice *) { return false; }
+ bool noticeDevicesChanged(const QPtrList<IRadioDevice> &) { return false; }
+ bool noticeDeviceDescriptionChanged(const QString &) { return false; }
+
+
+protected:
+ void activateStation(int i);
+ bool checkActions(const QString &string, int repeat_counter, const QMap<LIRC_Actions, QString> &map);
+
+protected slots:
+ void slotLIRC(int socket);
+ void slotKbdTimedOut();
+
+signals:
+
+ void sigUpdateConfig();
+
+ void sigRawLIRCSignal(const QString &what, int repeat_counter, bool &consumed);
+
+protected:
+
+#ifdef HAVE_LIRC
+ QSocketNotifier *m_lirc_notify;
+ int m_fd_lirc;
+ struct lirc_config *m_lircConfig;
+#endif
+
+ QTimer *m_kbdTimer;
+ int m_addIndex;
+ bool m_TakeRawLIRC;
+
+ QMap<LIRC_Actions, QString> m_Actions;
+ QMap<LIRC_Actions, QString> m_AlternativeActions;
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/lirc/listviewitem_lirc.cpp b/kradio3/plugins/lirc/listviewitem_lirc.cpp
new file mode 100644
index 0000000..4f7d0ce
--- /dev/null
+++ b/kradio3/plugins/lirc/listviewitem_lirc.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ listviewitem_lirc.cpp - description
+ -------------------
+ begin : Sun Aug 14 2005
+ copyright : (C) 2005 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 "listviewitem_lirc.h"
+
+ListViewItemLirc::ListViewItemLirc(QListView *parent, QListViewItem *after)
+ : KListViewItem(parent, after),
+ m_renamingInProcess(-1)
+{
+}
+
+ListViewItemLirc::~ListViewItemLirc()
+{
+}
+
+void ListViewItemLirc::startRename(int col)
+{
+ KListViewItem::startRename(col);
+ m_renamingInProcess = col;
+ emit sigRenamingStarted(this, col);
+}
+
+void ListViewItemLirc::okRename(int col)
+{
+ KListViewItem::okRename(col);
+ m_renamingInProcess = -1;
+ emit sigRenamingStopped(this, col);
+}
+
+void ListViewItemLirc::cancelRename(int col)
+{
+ KListViewItem::cancelRename(col);
+ m_renamingInProcess = -1;
+ emit sigRenamingStopped(this, col);
+}
+
+#include "listviewitem_lirc.moc"
diff --git a/kradio3/plugins/lirc/listviewitem_lirc.h b/kradio3/plugins/lirc/listviewitem_lirc.h
new file mode 100644
index 0000000..051ff76
--- /dev/null
+++ b/kradio3/plugins/lirc/listviewitem_lirc.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ listviewitem_lirc.cpp - description
+ -------------------
+ begin : Sun Aug 14 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef LISTVIEWITEM_LIRC_H
+#define LISTVIEWITEM_LIRC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <klistview.h>
+
+class ListViewItemLirc : public QObject, public KListViewItem
+{
+Q_OBJECT
+public:
+ ListViewItemLirc(QListView *parent, QListViewItem *after);
+ ~ListViewItemLirc();
+
+ bool isRenamingInProcess() const { return m_renamingInProcess >= 0; }
+ int getRenamingColumn() const { return m_renamingInProcess; }
+
+ virtual void startRename(int col);
+ virtual void okRename(int col);
+ virtual void cancelRename(int col);
+
+signals:
+
+ void sigRenamingStarted(ListViewItemLirc *sender, int column);
+ void sigRenamingStopped(ListViewItemLirc *sender, int column);
+
+protected:
+
+ int m_renamingInProcess;
+};
+
+#endif
diff --git a/kradio3/plugins/lirc/po/Makefile.am b/kradio3/plugins/lirc/po/Makefile.am
new file mode 100644
index 0000000..22fce99
--- /dev/null
+++ b/kradio3/plugins/lirc/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-lirc
+POFILES = AUTO
diff --git a/kradio3/plugins/lirc/po/de.po b/kradio3/plugins/lirc/po/de.po
new file mode 100644
index 0000000..1521094
--- /dev/null
+++ b/kradio3/plugins/lirc/po/de.po
@@ -0,0 +1,213 @@
+# translation of de.po to
+# translation of kradio-lirc.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:20+0100\n"
+"PO-Revision-Date: 2006-11-06 01:32+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file lirc-configuration-ui.ui line 17
+#: rc.cpp:3 rc.cpp:18 lirc-configuration-ui.cpp:75
+#, no-c-format
+msgid "LIRCConfigurationUI"
+msgstr "LIRCConfigurationUI"
+
+#. i18n: file lirc-configuration-ui.ui line 26
+#: rc.cpp:6 rc.cpp:21 lirc-configuration-ui.cpp:34
+#: lirc-configuration-ui.cpp:76
+#, no-c-format
+msgid "Action"
+msgstr "Aktion"
+
+#. i18n: file lirc-configuration-ui.ui line 37
+#: rc.cpp:9 rc.cpp:24 lirc-configuration-ui.cpp:35
+#: lirc-configuration-ui.cpp:77
+#, no-c-format
+msgid "LIRC String"
+msgstr "LIRC-Zeichenkette"
+
+#. i18n: file lirc-configuration-ui.ui line 48
+#: rc.cpp:12 rc.cpp:27 lirc-configuration-ui.cpp:36
+#: lirc-configuration-ui.cpp:78
+#, no-c-format
+msgid "Alternative LIRC String"
+msgstr "Alternative LIRC-Zeichenkette"
+
+#. i18n: file lirc-configuration-ui.ui line 98
+#: rc.cpp:15 rc.cpp:30 lirc-configuration-ui.cpp:79
+#, no-c-format
+msgid "textLabel1"
+msgstr "textLabel1"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: lirc-configuration.cpp:34
+msgid "digit 0"
+msgstr "Ziffer 0"
+
+#: lirc-configuration.cpp:35
+msgid "digit 1"
+msgstr "Ziffer 1"
+
+#: lirc-configuration.cpp:36
+msgid "digit 2"
+msgstr "Ziffer 2"
+
+#: lirc-configuration.cpp:37
+msgid "digit 3"
+msgstr "Ziffer 3"
+
+#: lirc-configuration.cpp:38
+msgid "digit 4"
+msgstr "Ziffer 4"
+
+#: lirc-configuration.cpp:39
+msgid "digit 5"
+msgstr "Ziffer 5"
+
+#: lirc-configuration.cpp:40
+msgid "digit 6"
+msgstr "Ziffer 6"
+
+#: lirc-configuration.cpp:41
+msgid "digit 7"
+msgstr "Ziffer 7"
+
+#: lirc-configuration.cpp:42
+msgid "digit 8"
+msgstr "Ziffer 8"
+
+#: lirc-configuration.cpp:43
+msgid "digit 9"
+msgstr "Ziffer 9"
+
+#: lirc-configuration.cpp:44
+msgid "Power On"
+msgstr "Einschalten"
+
+#: lirc-configuration.cpp:45
+msgid "Power Off"
+msgstr "Ausschalten"
+
+#: lirc-configuration.cpp:46
+msgid "Pause"
+msgstr "Pause"
+
+#: lirc-configuration.cpp:47
+msgid "Start Recording"
+msgstr "Aufnahme starten"
+
+#: lirc-configuration.cpp:48
+msgid "Stop Recording"
+msgstr "Aufnahme beenden"
+
+#: lirc-configuration.cpp:49
+msgid "Increase Volume"
+msgstr "Lautstärke erhöhen"
+
+#: lirc-configuration.cpp:50
+msgid "Decrease Volume"
+msgstr "Lautstärke senken"
+
+#: lirc-configuration.cpp:51
+msgid "Next Channel"
+msgstr "Nächster Sender"
+
+#: lirc-configuration.cpp:52
+msgid "Previous Channel"
+msgstr "Vorheriger Sender"
+
+#: lirc-configuration.cpp:53
+msgid "Search Next Channel"
+msgstr "Suche nächsten Sender"
+
+#: lirc-configuration.cpp:54
+msgid "Search Previous Channel"
+msgstr "Suche vorherigen Sender"
+
+#: lirc-configuration.cpp:55
+msgid "Enable Sleep Countdown"
+msgstr "Schlummer-Countdown aktivieren"
+
+#: lirc-configuration.cpp:56
+msgid "Quit KRadio"
+msgstr "KRadio Beenden"
+
+#: lirc-configuration.cpp:176
+msgid ""
+"Enter the key string of your remote or just press the button on your remote "
+"control"
+msgstr ""
+"Geben Sie die Zeichenkette Ihrer Fernsteuerung ein oder drücken Sie die "
+"Taste auf Ihrer Fernsteuerung"
+
+#: lirc-configuration.cpp:182
+msgid "Double Click on the entries to change the assignments"
+msgstr "Doppelklicken Sie auf die Einträge um die Zuordnung zu ändern"
+
+#: lircsupport.cpp:45
+msgid "Linux Infrared Control (LIRC) Support"
+msgstr "Unterstützung für die Fernsteuerung (LIRC)"
+
+#: lircsupport.cpp:51 lircsupport.cpp:330
+msgid "LIRC Plugin"
+msgstr "Plugin für die Fernsteuerung (LIRC)"
+
+#: lircsupport.cpp:56 lircsupport.cpp:57
+msgid "initializing kradio lirc plugin"
+msgstr "initialisiere das Plugin für die Fernsteuerung (LIRC)"
+
+#: lircsupport.cpp:65
+msgid ""
+"%1 does not exist. File was created with KRadio's default .lircrc proposal"
+msgstr ""
+"Die Datei %1 existiert nicht. Die Datei wurde mit den Defaulteinstellungen "
+"für KRadio erzeugt."
+
+#: lircsupport.cpp:94
+msgid "There is no entry for kradio in any of your .lircrc files."
+msgstr "Es gibt keinen Eintrag für KRadio in jeglichen .lirc-Dateien"
+
+#: lircsupport.cpp:95
+msgid "Please setup your .lircrc files correctly."
+msgstr "Bitte konfigurieren Sie Ihre .lirc-Dateien richtig."
+
+#: lircsupport.cpp:106 lircsupport.cpp:107
+msgid "Initializing kradio lirc plugin failed"
+msgstr "Die Initialisierung des KRadio LIRC Plugins schlug fehl"
+
+#: lircsupport.cpp:109 lircsupport.cpp:110
+msgid "Initializing kradio lirc plugin successful"
+msgstr "Die Initialisierung des LIRC Plugins war erfolgreich"
+
+#: lircsupport.cpp:167
+msgid ""
+"Reading from LIRC socket failed. Disabling LIRC Functions till next start of "
+"kradio"
+msgstr ""
+"Das Lesen vom LIRC-Socket ist fehlgeschlagen. Die LIRC-Funktion wird bis zum "
+"nächsten Start von KRadio temporär abgeschaltet."
+
+#: lircsupport.cpp:329
+msgid "LIRC Support"
+msgstr "Fernsteuerung"
diff --git a/kradio3/plugins/lirc/po/ru.po b/kradio3/plugins/lirc/po/ru.po
new file mode 100644
index 0000000..54edb74
--- /dev/null
+++ b/kradio3/plugins/lirc/po/ru.po
@@ -0,0 +1,209 @@
+# translation of ru.po to
+# translation of kradio-lirc.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:20+0100\n"
+"PO-Revision-Date: 2006-11-08 12:54+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file lirc-configuration-ui.ui line 17
+#: rc.cpp:3 rc.cpp:18 lirc-configuration-ui.cpp:75
+#, no-c-format
+msgid "LIRCConfigurationUI"
+msgstr "LIRCConfigurationUI"
+
+#. i18n: file lirc-configuration-ui.ui line 26
+#: rc.cpp:6 rc.cpp:21 lirc-configuration-ui.cpp:34
+#: lirc-configuration-ui.cpp:76
+#, no-c-format
+msgid "Action"
+msgstr "Действие"
+
+#. i18n: file lirc-configuration-ui.ui line 37
+#: rc.cpp:9 rc.cpp:24 lirc-configuration-ui.cpp:35
+#: lirc-configuration-ui.cpp:77
+#, no-c-format
+msgid "LIRC String"
+msgstr "Строка LIRC"
+
+#. i18n: file lirc-configuration-ui.ui line 48
+#: rc.cpp:12 rc.cpp:27 lirc-configuration-ui.cpp:36
+#: lirc-configuration-ui.cpp:78
+#, no-c-format
+msgid "Alternative LIRC String"
+msgstr "Альтернативная строка LIRC"
+
+#. i18n: file lirc-configuration-ui.ui line 98
+#: rc.cpp:15 rc.cpp:30 lirc-configuration-ui.cpp:79
+#, no-c-format
+msgid "textLabel1"
+msgstr "textLabel1"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: lirc-configuration.cpp:34
+msgid "digit 0"
+msgstr "ноль"
+
+#: lirc-configuration.cpp:35
+msgid "digit 1"
+msgstr "один"
+
+#: lirc-configuration.cpp:36
+msgid "digit 2"
+msgstr "два"
+
+#: lirc-configuration.cpp:37
+msgid "digit 3"
+msgstr "три"
+
+#: lirc-configuration.cpp:38
+msgid "digit 4"
+msgstr "четыре"
+
+#: lirc-configuration.cpp:39
+msgid "digit 5"
+msgstr "пять"
+
+#: lirc-configuration.cpp:40
+msgid "digit 6"
+msgstr "шесть"
+
+#: lirc-configuration.cpp:41
+msgid "digit 7"
+msgstr "семь"
+
+#: lirc-configuration.cpp:42
+msgid "digit 8"
+msgstr "восемь"
+
+#: lirc-configuration.cpp:43
+msgid "digit 9"
+msgstr "девять"
+
+#: lirc-configuration.cpp:44
+msgid "Power On"
+msgstr "Включить"
+
+#: lirc-configuration.cpp:45
+msgid "Power Off"
+msgstr "Выключить"
+
+#: lirc-configuration.cpp:46
+msgid "Pause"
+msgstr "Приостановить"
+
+#: lirc-configuration.cpp:47
+msgid "Start Recording"
+msgstr "Начать запись"
+
+#: lirc-configuration.cpp:48
+msgid "Stop Recording"
+msgstr "Остановить запись"
+
+#: lirc-configuration.cpp:49
+msgid "Increase Volume"
+msgstr "Увеличить громкость"
+
+#: lirc-configuration.cpp:50
+msgid "Decrease Volume"
+msgstr "Уменьшить громкость"
+
+#: lirc-configuration.cpp:51
+msgid "Next Channel"
+msgstr "Следующий канал"
+
+#: lirc-configuration.cpp:52
+msgid "Previous Channel"
+msgstr "Предыдущий канал"
+
+#: lirc-configuration.cpp:53
+msgid "Search Next Channel"
+msgstr "Поиск следующего канала"
+
+#: lirc-configuration.cpp:54
+msgid "Search Previous Channel"
+msgstr "Поиск предыдущего канала"
+
+#: lirc-configuration.cpp:55
+msgid "Enable Sleep Countdown"
+msgstr "Включить таймер отключения"
+
+#: lirc-configuration.cpp:56
+msgid "Quit KRadio"
+msgstr "Закрыть KRadio"
+
+#: lirc-configuration.cpp:176
+msgid ""
+"Enter the key string of your remote or just press the button on your remote "
+"control"
+msgstr "Введите ключевую строку вашего ПДУ либо просто нажмите кнопку на нём"
+
+#: lirc-configuration.cpp:182
+msgid "Double Click on the entries to change the assignments"
+msgstr "Для изменения привязки дважды щёлкните по ней мышью"
+
+#: lircsupport.cpp:45
+msgid "Linux Infrared Control (LIRC) Support"
+msgstr "Поддержка ПДУ в Linux (LIRC)"
+
+#: lircsupport.cpp:51 lircsupport.cpp:330
+msgid "LIRC Plugin"
+msgstr "Модуль ДУ (LIRC)"
+
+#: lircsupport.cpp:56 lircsupport.cpp:57
+msgid "initializing kradio lirc plugin"
+msgstr "Инициализация модуля LIRC"
+
+#: lircsupport.cpp:65
+msgid ""
+"%1 does not exist. File was created with KRadio's default .lircrc proposal"
+msgstr "%1 не существует. Был создан файл .lircrc для KRadio по умолчанию"
+
+#: lircsupport.cpp:94
+msgid "There is no entry for kradio in any of your .lircrc files."
+msgstr "Ни в одном из ваших файлов .lircrc нет упоминания о KRadio."
+
+#: lircsupport.cpp:95
+msgid "Please setup your .lircrc files correctly."
+msgstr "Настройте файлы .lircrc"
+
+#: lircsupport.cpp:106 lircsupport.cpp:107
+msgid "Initializing kradio lirc plugin failed"
+msgstr "Инициализация модуля LIRC не удалась"
+
+#: lircsupport.cpp:109 lircsupport.cpp:110
+msgid "Initializing kradio lirc plugin successful"
+msgstr "Модуль LIRC инициализирован"
+
+#: lircsupport.cpp:167
+msgid ""
+"Reading from LIRC socket failed. Disabling LIRC Functions till next start of "
+"kradio"
+msgstr ""
+"Чтение из сокета LIRC не удалось. Отключаю функции LIRC до следующего "
+"запуска KRadio."
+
+#: lircsupport.cpp:329
+msgid "LIRC Support"
+msgstr "Поддержка LIRC"
diff --git a/kradio3/plugins/oss-sound/Makefile.am b/kradio3/plugins/oss-sound/Makefile.am
new file mode 100644
index 0000000..ffdd5be
--- /dev/null
+++ b/kradio3/plugins/oss-sound/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = liboss-sound.la
+liboss_sound_la_SOURCES = oss-sound.cpp oss-sound-configuration-ui.ui \
+ oss-sound-configuration.cpp
+liboss_sound_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = oss-sound.h oss-sound-configuration.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-oss-sound.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-oss-sound.pot
diff --git a/kradio3/plugins/oss-sound/icons/Makefile.am b/kradio3/plugins/oss-sound/icons/Makefile.am
new file mode 100644
index 0000000..b3f2583
--- /dev/null
+++ b/kradio3/plugins/oss-sound/icons/Makefile.am
@@ -0,0 +1,2 @@
+icons_ICON = AUTO
+iconsdir = $(kde_datadir)/kradio/icons
diff --git a/kradio3/plugins/oss-sound/icons/hi16-action-kradio_oss.png b/kradio3/plugins/oss-sound/icons/hi16-action-kradio_oss.png
new file mode 100644
index 0000000..1241b1f
--- /dev/null
+++ b/kradio3/plugins/oss-sound/icons/hi16-action-kradio_oss.png
Binary files differ
diff --git a/kradio3/plugins/oss-sound/icons/hi32-action-kradio_oss.png b/kradio3/plugins/oss-sound/icons/hi32-action-kradio_oss.png
new file mode 100644
index 0000000..85e5c63
--- /dev/null
+++ b/kradio3/plugins/oss-sound/icons/hi32-action-kradio_oss.png
Binary files differ
diff --git a/kradio3/plugins/oss-sound/icons/hi48-action-kradio_oss.png b/kradio3/plugins/oss-sound/icons/hi48-action-kradio_oss.png
new file mode 100644
index 0000000..2d2a08d
--- /dev/null
+++ b/kradio3/plugins/oss-sound/icons/hi48-action-kradio_oss.png
Binary files differ
diff --git a/kradio3/plugins/oss-sound/oss-sound-configuration-ui.ui b/kradio3/plugins/oss-sound/oss-sound-configuration-ui.ui
new file mode 100644
index 0000000..7cf3483
--- /dev/null
+++ b/kradio3/plugins/oss-sound/oss-sound-configuration-ui.ui
@@ -0,0 +1,132 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>OSSSoundConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>OSSSoundConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>562</width>
+ <height>411</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupBox20</cstring>
+ </property>
+ <property name="title">
+ <string>Devices</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>editMixerDevice</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>editDSPDevice</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Device</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Mixer Device</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="2" column="1">
+ <property name="name">
+ <cstring>editBufferSize</cstring>
+ </property>
+ <property name="suffix">
+ <string> kB</string>
+ </property>
+ <property name="maxValue">
+ <number>1024</number>
+ </property>
+ <property name="minValue">
+ <number>4</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox21</cstring>
+ </property>
+ <property name="title">
+ <string>Extended Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>chkDisablePlayback</cstring>
+ </property>
+ <property name="text">
+ <string>Disable Playback</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>chkDisableCapture</cstring>
+ </property>
+ <property name="text">
+ <string>Disable Capture</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/oss-sound/oss-sound-configuration.cpp b/kradio3/plugins/oss-sound/oss-sound-configuration.cpp
new file mode 100644
index 0000000..5665114
--- /dev/null
+++ b/kradio3/plugins/oss-sound/oss-sound-configuration.cpp
@@ -0,0 +1,86 @@
+/***************************************************************************
+ oss-sound-configuration.cpp - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 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 <qcheckbox.h>
+
+#include <kurlrequester.h>
+#include <knuminput.h>
+
+#include "oss-sound-configuration.h"
+#include "oss-sound.h"
+
+OSSSoundConfiguration::OSSSoundConfiguration (QWidget *parent, OSSSoundDevice *dev)
+ : OSSSoundConfigurationUI(parent),
+ m_SoundDevice (dev),
+ m_dirty(true),
+ m_ignore_gui_updates(false)
+{
+ connect(editDSPDevice, SIGNAL(textChanged(const QString &)), this, SLOT(slotSetDirty()));
+ connect(editMixerDevice, SIGNAL(textChanged(const QString &)), this, SLOT(slotSetDirty()));
+ connect(editBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+ connect(chkDisablePlayback, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+ connect(chkDisableCapture, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+ slotCancel();
+}
+
+
+OSSSoundConfiguration::~OSSSoundConfiguration ()
+{
+}
+
+
+void OSSSoundConfiguration::slotOK()
+{
+ if (m_SoundDevice && m_dirty) {
+ m_SoundDevice->setBufferSize ( editBufferSize ->value() * 1024);
+ m_SoundDevice->enablePlayback (!chkDisablePlayback->isChecked());
+ m_SoundDevice->enableCapture (!chkDisableCapture ->isChecked());
+ m_SoundDevice->setDSPDeviceName ( editDSPDevice ->url());
+ m_SoundDevice->setMixerDeviceName( editMixerDevice ->url());
+ m_dirty = false;
+ }
+}
+
+
+void OSSSoundConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ m_ignore_gui_updates = true;
+ editDSPDevice ->setURL (m_SoundDevice ? m_SoundDevice->getDSPDeviceName() : QString::null);
+ editMixerDevice ->setURL (m_SoundDevice ? m_SoundDevice->getMixerDeviceName() : QString::null);
+ editBufferSize ->setValue (m_SoundDevice ? m_SoundDevice->getBufferSize()/1024 : 4);
+ chkDisablePlayback->setChecked(m_SoundDevice ? !m_SoundDevice->isPlaybackEnabled() : false);
+ chkDisableCapture ->setChecked(m_SoundDevice ? !m_SoundDevice->isCaptureEnabled() : false);
+ m_ignore_gui_updates = false;
+ m_dirty = false;
+ }
+}
+
+void OSSSoundConfiguration::slotUpdateConfig()
+{
+ slotSetDirty();
+ slotCancel();
+}
+
+void OSSSoundConfiguration::slotSetDirty()
+{
+ if (!m_ignore_gui_updates) {
+ m_dirty = true;
+ }
+}
+
+#include "oss-sound-configuration.moc"
diff --git a/kradio3/plugins/oss-sound/oss-sound-configuration.h b/kradio3/plugins/oss-sound/oss-sound-configuration.h
new file mode 100644
index 0000000..9106821
--- /dev/null
+++ b/kradio3/plugins/oss-sound/oss-sound-configuration.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ oss-sound-configuration.h - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_OSS_SOUND_CONFIGURATION_H
+#define KRADIO_OSS_SOUND_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "oss-sound-configuration-ui.h"
+#include "oss-sound.h"
+
+class OSSSoundConfiguration : public OSSSoundConfigurationUI
+{
+Q_OBJECT
+public :
+ OSSSoundConfiguration (QWidget *parent, OSSSoundDevice *);
+ ~OSSSoundConfiguration ();
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+ void slotUpdateConfig();
+
+protected:
+
+ OSSSoundDevice *m_SoundDevice;
+
+ bool m_dirty;
+ bool m_ignore_gui_updates;
+};
+
+#endif
diff --git a/kradio3/plugins/oss-sound/oss-sound.cpp b/kradio3/plugins/oss-sound/oss-sound.cpp
new file mode 100644
index 0000000..760399e
--- /dev/null
+++ b/kradio3/plugins/oss-sound/oss-sound.cpp
@@ -0,0 +1,991 @@
+/***************************************************************************
+ oss-sound.cpp - description
+ -------------------
+ begin : Sun Mar 21 2004
+ copyright : (C) 2004 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 "oss-sound.h"
+
+#include "../../src/include/aboutwidget.h"
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/soundcard.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+#include <errno.h>
+
+#include "oss-sound-configuration.h"
+#include "../../src/include/utils.h"
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS(OSSSoundDevice, "kradio-oss-sound", i18n("Open Sound System (OSS) Support"));
+
+/////////////////////////////////////////////////////////////////////////////
+
+struct _lrvol { unsigned char l, r; short dummy; };
+
+OSSSoundDevice::OSSSoundDevice(const QString &name)
+ : QObject(NULL, NULL),
+ PluginBase(name, i18n("KRadio OSS Sound Plugin")),
+ m_DSPDeviceName(""),
+ m_MixerDeviceName(""),
+ m_DSP_fd(-1),
+ m_Mixer_fd(-1),
+ m_DuplexMode(DUPLEX_UNKNOWN),
+ m_DSPFormat(),
+ m_PassivePlaybackStreams(),
+ m_PlaybackStreamID(),
+ m_CaptureStreamID(),
+ m_BufferSize(65536),
+ m_PlaybackBuffer(m_BufferSize),
+ m_CaptureBuffer(m_BufferSize),
+ m_CaptureRequestCounter(0),
+ m_CapturePos(0),
+ m_CaptureStartTime(0),
+ //m_PlaybackSkipCount(0),
+ m_CaptureSkipCount(0),
+ m_EnablePlayback(true),
+ m_EnableCapture(true)
+{
+ QObject::connect(&m_PollingTimer, SIGNAL(timeout()), this, SLOT(slotPoll()));
+}
+
+
+OSSSoundDevice::~OSSSoundDevice()
+{
+ stopCapture(m_CaptureStreamID);
+ stopPlayback(m_PlaybackStreamID);
+ closeDSPDevice();
+ closeMixerDevice();
+}
+
+
+bool OSSSoundDevice::connectI(Interface *i)
+{
+ bool a = PluginBase::connectI(i);
+ bool b = ISoundStreamClient::connectI(i);
+ return a || b;
+}
+
+
+bool OSSSoundDevice::disconnectI(Interface *i)
+{
+ bool a = PluginBase::disconnectI(i);
+ bool b = ISoundStreamClient::disconnectI(i);
+ return a || b;
+}
+
+void OSSSoundDevice::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_sendReleasePlayback(this);
+ s->register4_sendReleaseCapture(this);
+ s->register4_sendPlaybackVolume(this);
+ s->register4_sendCaptureVolume(this);
+ s->register4_queryPlaybackVolume(this);
+ s->register4_queryCaptureVolume(this);
+ s->register4_sendStartPlayback(this);
+ s->register4_sendPausePlayback(this);
+ s->register4_sendStopPlayback(this);
+ s->register4_queryIsPlaybackRunning(this);
+ s->register4_sendStartCaptureWithFormat(this);
+ s->register4_sendStopCapture(this);
+ s->register4_queryIsCaptureRunning(this);
+ s->register4_notifySoundStreamClosed(this);
+ s->register4_notifySoundStreamRedirected(this);
+ s->register4_notifySoundStreamData(this);
+ }
+}
+
+// PluginBase
+
+void OSSSoundDevice::saveState (KConfig *c) const
+{
+ c->setGroup(QString("oss-sound-") + PluginBase::name());
+
+ c->writeEntry("dsp-device", m_DSPDeviceName);
+ c->writeEntry("mixer-device", m_MixerDeviceName);
+ c->writeEntry("enable-playback", m_EnablePlayback);
+ c->writeEntry("enable-capture", m_EnableCapture);
+ c->writeEntry("buffer-size", m_BufferSize);
+ c->writeEntry("soundstreamclient-id", m_SoundStreamClientID);
+}
+
+
+void OSSSoundDevice::restoreState (KConfig *c)
+{
+ c->setGroup(QString("oss-sound-") + PluginBase::name());
+
+ m_EnablePlayback = c->readBoolEntry("enable-playback", true);
+ m_EnableCapture = c->readBoolEntry("enable-capture", true);
+ m_BufferSize = c->readNumEntry ("buffer-size", 65536);
+
+ setDSPDeviceName (c->readEntry ("dsp-device", "/dev/dsp"));
+ setMixerDeviceName (c->readEntry ("mixer-device", "/dev/mixer"));
+
+ m_PlaybackBuffer.resize(m_BufferSize);
+ m_CaptureBuffer.resize(m_BufferSize);
+
+ setSoundStreamClientID(c->readEntry("soundstreamclient-id", getSoundStreamClientID()));
+
+ emit sigUpdateConfig();
+}
+
+
+void OSSSoundDevice::setMixerDeviceName(const QString &dev_name)
+{
+ if (m_MixerDeviceName != dev_name) {
+ m_MixerDeviceName = dev_name;
+ if (m_Mixer_fd >= 0)
+ openMixerDevice(true);
+ getMixerChannels(SOUND_MIXER_DEVMASK, m_PlaybackChannels, m_revPlaybackChannels);
+ getMixerChannels(SOUND_MIXER_RECMASK, m_CaptureChannels, m_revCaptureChannels);
+ notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannels);
+ notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannels);
+ }
+}
+
+
+ConfigPageInfo OSSSoundDevice::createConfigurationPage()
+{
+ OSSSoundConfiguration *conf = new OSSSoundConfiguration(NULL, this);
+ QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig()));
+ return ConfigPageInfo (conf,
+ i18n("OSS Sound"),
+ i18n("OSS Sound Device Options"),
+ "kradio_oss");
+}
+
+
+AboutPageInfo OSSSoundDevice::createAboutPage()
+{
+/* KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("OSS Sound Plugin for KRadio"),
+ KAboutData::License_GPL,
+ "(c) 2004 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/kradio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed),
+ i18n("OSS Sound"),
+ i18n("OSS Sound"),
+ "kradio_oss_sound"
+ );
+*/
+ return AboutPageInfo();
+}
+
+
+
+bool OSSSoundDevice::preparePlayback(SoundStreamID id, const QString &channel, bool active_mode, bool start_immediately)
+{
+ if (id.isValid() && m_revPlaybackChannels.contains(channel)) {
+ m_PlaybackStreams.insert(id, SoundStreamConfig(m_revPlaybackChannels[channel], active_mode));
+ if (start_immediately)
+ startPlayback(id);
+ return true;
+ // FIXME: what to do if stream is already playing?
+ }
+ return false;
+}
+
+
+bool OSSSoundDevice::prepareCapture(SoundStreamID id, const QString &channel)
+{
+ if (id.isValid() && m_revCaptureChannels.contains(channel)) {
+ m_CaptureStreams.insert(id, SoundStreamConfig(m_revCaptureChannels[channel]));
+ return true;
+ // FIXME: what to do if stream is already playing?
+ }
+ return false;
+}
+
+bool OSSSoundDevice::releasePlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id)) {
+ if (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ stopPlayback(id);
+ }
+ m_PlaybackStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool OSSSoundDevice::releaseCapture(SoundStreamID id)
+{
+ if (id.isValid() && m_CaptureStreams.contains(id)) {
+ if (m_CaptureStreamID == id) {
+ stopCapture(id);
+ }
+ m_CaptureStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool OSSSoundDevice::supportsPlayback() const
+{
+ return m_EnablePlayback;
+}
+
+
+bool OSSSoundDevice::supportsCapture() const
+{
+ return m_EnableCapture;
+}
+
+
+bool OSSSoundDevice::startPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id) && m_EnablePlayback) {
+
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ bool ok = false;
+ if (cfg.m_ActiveMode) {
+ if (!m_PlaybackStreamID.isValid()) {
+ m_PlaybackStreamID = id;
+ ok = true;
+ }
+ } else {
+ if (!m_PassivePlaybackStreams.contains(id))
+ m_PassivePlaybackStreams.append(id);
+ ok = true;
+ }
+
+ if (ok) {
+ openMixerDevice();
+ if (cfg.m_Volume >= 0)
+ writeMixerVolume(cfg.m_Channel, cfg.m_Volume);
+ }
+
+ // error handling?
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool OSSSoundDevice::pausePlayback(SoundStreamID /*id*/)
+{
+ //return stopPlayback(id);
+ return false;
+}
+
+
+bool OSSSoundDevice::stopPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id)) {
+
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ if (!cfg.m_ActiveMode) {
+ if (m_PassivePlaybackStreams.contains(id)) {
+// writeMixerVolume(cfg.m_Channel, 0);
+ m_PassivePlaybackStreams.remove(id);
+ }
+ } else if (m_PlaybackStreamID == id) {
+ m_PlaybackStreamID = SoundStreamID::InvalidID;
+ m_PlaybackBuffer.clear();
+ closeDSPDevice();
+ }
+
+ closeMixerDevice();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool OSSSoundDevice::isPlaybackRunning(SoundStreamID id, bool &b) const
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id)) {
+ b = true;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool OSSSoundDevice::startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format)
+{
+ if (m_CaptureStreams.contains(id) && m_EnableCapture) {
+
+ if (m_CaptureStreamID != id) {
+ m_CapturePos = 0;
+ m_CaptureStartTime = time(NULL);
+ }
+
+ if (m_CaptureStreamID != id || force_format) {
+
+ m_CaptureStreamID = id;
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ openMixerDevice();
+ selectCaptureChannel(cfg.m_Channel);
+ if (cfg.m_Volume >= 0)
+ writeMixerVolume(cfg.m_Channel, cfg.m_Volume);
+
+ openDSPDevice(proposed_format);
+
+ // FIXME: error handling?
+ }
+
+ real_format = m_DSPFormat;
+ m_CaptureRequestCounter++;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool OSSSoundDevice::stopCapture(SoundStreamID id)
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+
+ if (--m_CaptureRequestCounter == 0) {
+ m_CaptureStreamID = SoundStreamID::InvalidID;
+ m_CaptureBuffer.clear();
+
+ closeMixerDevice();
+ closeDSPDevice();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool OSSSoundDevice::isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ b = true;
+ sf = m_DSPFormat;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool OSSSoundDevice::noticeSoundStreamClosed(SoundStreamID id)
+{
+ bool found = false;
+ if (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ stopPlayback(id);
+ found = true;
+ }
+ if (m_CaptureStreamID == id) {
+ stopCapture(id);
+ found = true;
+ }
+ m_PlaybackStreams.remove(id);
+ m_CaptureStreams.remove(id);
+ return found;
+}
+
+
+bool OSSSoundDevice::noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID)
+{
+ bool found = false;
+ if (m_PlaybackStreams.contains(oldID)) {
+ m_PlaybackStreams.insert(newID, m_PlaybackStreams[oldID]);
+ if (newID != oldID)
+ m_PlaybackStreams.remove(oldID);
+ found = true;
+ }
+ if (m_CaptureStreams.contains(oldID)) {
+ m_CaptureStreams.insert(newID, m_CaptureStreams[oldID]);
+ if (newID != oldID)
+ m_CaptureStreams.remove(oldID);
+ found = true;
+ }
+
+ if (m_PlaybackStreamID == oldID)
+ m_PlaybackStreamID = newID;
+ if (m_CaptureStreamID == oldID)
+ m_CaptureStreamID = newID;
+ if (m_PassivePlaybackStreams.contains(oldID)) {
+ m_PassivePlaybackStreams.remove(oldID);
+ m_PassivePlaybackStreams.append(newID);
+ }
+ return found;
+}
+
+
+bool OSSSoundDevice::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &format,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &/*md*/
+ )
+{
+ if (!id.isValid() || id != m_PlaybackStreamID)
+ return false;
+
+ if (m_DSP_fd < 0) {
+ openDSPDevice(format);
+ } else if (format != m_DSPFormat) {
+ if (m_CaptureStreamID.isValid())
+ return false;
+
+ // flush playback buffer
+ size_t buffersize = 0;
+ char *buffer = m_PlaybackBuffer.getData(buffersize);
+ write(m_DSP_fd, buffer, buffersize);
+
+ // if not all could be written, it must be discarded
+ m_PlaybackBuffer.clear();
+
+ closeDSPDevice();
+ openDSPDevice(format);
+ // error handling ?
+ }
+
+ size_t n = m_PlaybackBuffer.addData(data, size);
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? n : min(consumed_size, n);
+
+// if (n < size) {
+// m_PlaybackSkipCount += size - n;
+// } else if (m_PlaybackSkipCount > 0) {
+// logWarning(i18n("%1: Playback buffer overflow. Skipped %1 bytes").arg(m_DSPDeviceName).arg(QString::number(m_PlaybackSkipCount)));
+// m_PlaybackSkipCount = 0;
+// }
+
+ return true; //m_PlaybackSkipCount == 0;
+}
+
+
+
+void OSSSoundDevice::slotPoll()
+{
+ int err = 0;
+
+ if (m_CaptureStreamID.isValid() && m_DSP_fd >= 0) {
+
+ size_t bufferSize = 0;
+ char *buffer = m_CaptureBuffer.getFreeSpace(bufferSize);
+
+ int bytesRead = read(m_DSP_fd, buffer, bufferSize);
+
+ if (bytesRead > 0) {
+ m_CaptureBuffer.removeFreeSpace(bytesRead);
+ } else if (bytesRead < 0 && errno == EAGAIN) {
+ bytesRead = 0;
+ } else if (bytesRead == 0) {
+ err = -1;
+ logError(i18n("OSS device %1: No data to record").arg(m_DSPDeviceName));
+ } else {
+ err = errno;
+ }
+
+ while (m_CaptureBuffer.getFillSize() > m_CaptureBuffer.getSize() / 3) {
+ size_t size = 0;
+ buffer = m_CaptureBuffer.getData(size);
+ time_t cur_time = time(NULL);
+ size_t consumed_size = SIZE_T_DONT_CARE;
+ notifySoundStreamData(m_CaptureStreamID, m_DSPFormat, buffer, size, consumed_size, SoundMetaData(m_CapturePos, cur_time - m_CaptureStartTime, cur_time, i18n("internal stream, not stored (%1)").arg(m_DSPDeviceName)));
+ if (consumed_size == SIZE_T_DONT_CARE)
+ consumed_size = size;
+ m_CaptureBuffer.removeData(consumed_size);
+ m_CapturePos += consumed_size;
+ if (consumed_size < size)
+ break;
+ }
+ }
+
+ if (m_PlaybackStreamID.isValid()/* && m_DSP_fd >= 0*/) {
+
+ if (m_PlaybackBuffer.getFillSize() > 0 && m_DSP_fd >= 0) {
+
+ size_t buffersize = 0;
+ char *buffer = m_PlaybackBuffer.getData(buffersize);
+ int bytesWritten = write(m_DSP_fd, buffer, buffersize);
+
+ if (bytesWritten > 0) {
+ m_PlaybackBuffer.removeData(bytesWritten);
+ } else if (bytesWritten < 0 && errno == EAGAIN) {
+ bytesWritten = 0;
+ } else {
+ err = errno;
+ }
+ }
+
+ if (m_PlaybackBuffer.getFreeSize() > 0)
+ notifyReadyForPlaybackData(m_PlaybackStreamID, m_PlaybackBuffer.getFreeSize());
+ }
+
+ if (err) {
+ logError(i18n("Error %1 while handling OSS device %2").arg(QString().setNum(err)).arg(m_DSPDeviceName));
+ }
+
+ if (m_PlaybackStreamID.isValid())
+ checkMixerVolume(m_PlaybackStreamID);
+ if (m_CaptureStreamID.isValid())
+ checkMixerVolume(m_CaptureStreamID);
+
+ QValueListConstIterator<SoundStreamID> end = m_PassivePlaybackStreams.end();
+ for (QValueListConstIterator<SoundStreamID> it = m_PassivePlaybackStreams.begin(); it != end; ++it)
+ checkMixerVolume(*it);
+
+}
+
+
+bool OSSSoundDevice::openDSPDevice(const SoundFormat &format, bool reopen)
+{
+ if (m_DSP_fd >= 0) {
+
+ if (reopen) {
+
+ closeDSPDevice ( /* force = */ true);
+
+ } else {
+
+ if (format != m_DSPFormat)
+ return false;
+
+ if (m_DuplexMode != DUPLEX_FULL && m_CaptureStreamID.isValid() && m_PlaybackStreamID.isValid())
+ return false;
+
+ return true;
+ }
+ } else {
+ if (reopen)
+ return true;
+ }
+
+ m_DSPFormat = format;
+
+ // first testopen for CAPS
+ m_DSP_fd = open(m_DSPDeviceName.ascii(), O_NONBLOCK | O_RDONLY);
+ bool err = m_DSP_fd < 0;
+ if (err) {
+ logError(i18n("Cannot open DSP device %1").arg(m_DSPDeviceName));
+ return false;
+ }
+ int caps = 0;
+ err |= (ioctl (m_DSP_fd, SNDCTL_DSP_GETCAPS, &caps) != 0);
+ if (err)
+ logError(i18n("Cannot read DSP capabilities for %1").arg(m_DSPDeviceName));
+
+ m_DuplexMode = (caps & DSP_CAP_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
+ close (m_DSP_fd);
+ m_DSP_fd = -1;
+
+ // opening and seeting up the device file
+ int mode = O_NONBLOCK;
+ if (m_DuplexMode == DUPLEX_FULL) {
+ mode |= O_RDWR;
+ } else if (m_CaptureStreamID.isValid()) {
+ mode |= O_RDONLY;
+ } else {
+ mode |= O_WRONLY;
+ }
+
+ m_DSP_fd = open(m_DSPDeviceName.ascii(), mode);
+
+ err = m_DSP_fd < 0;
+ if (err) {
+ logError(i18n("Cannot open DSP device %1").arg(m_DSPDeviceName));
+ return false;
+ }
+
+ int oss_format = getOSSFormat(m_DSPFormat);
+ err |= (ioctl(m_DSP_fd, SNDCTL_DSP_SETFMT, &oss_format) != 0);
+ if (err)
+ logError(i18n("Cannot set DSP sample format for %1").arg(m_DSPDeviceName));
+
+ int channels = m_DSPFormat.m_Channels;
+ err |= (ioctl(m_DSP_fd, SNDCTL_DSP_CHANNELS, &channels) != 0);
+ if (err)
+ logError(i18n("Cannot set number of channels for %1").arg(m_DSPDeviceName));
+
+ int rate = m_DSPFormat.m_SampleRate;
+ err |= (ioctl(m_DSP_fd, SNDCTL_DSP_SPEED, &rate) != 0);
+ if (err)
+ logError(i18n("Cannot set sampling rate for %1").arg(m_DSPDeviceName));
+ if (rate != (int)m_DSPFormat.m_SampleRate) {
+ logWarning(i18n("Asking for %1 Hz but %2 uses %3 Hz").
+ arg(QString::number(m_DSPFormat.m_SampleRate)).
+ arg(m_DSPDeviceName).
+ arg(QString::number(rate)));
+ m_DSPFormat.m_SampleRate = rate;
+ }
+
+ int stereo = m_DSPFormat.m_Channels == 2;
+ err |= (ioctl(m_DSP_fd, SNDCTL_DSP_STEREO, &stereo) != 0);
+ if (err)
+ logError(i18n("Cannot set stereo mode for %1").arg(m_DSPDeviceName));
+
+ unsigned sampleSize = m_DSPFormat.m_SampleBits;
+ err |= (ioctl(m_DSP_fd, SNDCTL_DSP_SAMPLESIZE, &sampleSize) != 0);
+ if (err || sampleSize != m_DSPFormat.m_SampleBits)
+ logError(i18n("Cannot set sample size for %1").arg(m_DSPDeviceName));
+
+ // setup buffer, ask for 40ms latency
+ int tmp = (400 * m_DSPFormat.frameSize() * m_DSPFormat.m_SampleRate) / 1000;
+ int mask = -1; for (; tmp; tmp >>= 1) ++mask;
+ if (mask < 8) mask = 12; // default 4kB
+ mask |= 0x7FFF0000;
+ err |= ioctl (m_DSP_fd, SNDCTL_DSP_SETFRAGMENT, &mask);
+ if (err)
+ logError(i18n("Cannot set buffers for %1").arg(m_DSPDeviceName));
+
+ int bufferBlockSize = 0;
+ err |= ioctl (m_DSP_fd, SNDCTL_DSP_GETBLKSIZE, &bufferBlockSize);
+ if (err) {
+ logError(i18n("Cannot read buffer size for %1").arg(m_DSPDeviceName));
+ } else {
+ logInfo(i18n("%1 uses buffer blocks of %2 bytes").arg(m_DSPDeviceName).arg(QString::number(bufferBlockSize)));
+ size_t tmp = (((m_BufferSize - 1) / bufferBlockSize) + 1) * bufferBlockSize;
+ setBufferSize(tmp);
+ logInfo(i18n("adjusted own buffer size to %1 bytes").arg(QString::number(tmp)));
+ }
+
+ int trigger = ~PCM_ENABLE_INPUT & ~PCM_ENABLE_OUTPUT;
+ ioctl(m_DSP_fd, SNDCTL_DSP_SETTRIGGER, &trigger);
+ trigger = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
+ ioctl(m_DSP_fd, SNDCTL_DSP_SETTRIGGER, &trigger);
+
+ if (!err) {
+ m_PollingTimer.start(40);
+ } else {
+ closeDSPDevice();
+ }
+
+ m_CaptureSkipCount = 0;
+ //m_PlaybackSkipCount = 0;
+
+ return !err;
+}
+
+
+bool OSSSoundDevice::closeDSPDevice(bool force)
+{
+ if ((!m_PlaybackStreamID.isValid() && !m_CaptureStreamID.isValid()) || force) {
+
+ if (m_Mixer_fd < 0)
+ m_PollingTimer.stop();
+
+ if (m_DSP_fd >= 0)
+ close (m_DSP_fd);
+ m_DSP_fd = -1;
+
+ m_PlaybackBuffer.clear();
+ m_CaptureBuffer.clear();
+ }
+ return true;
+}
+
+
+bool OSSSoundDevice::openMixerDevice(bool reopen)
+{
+ if (reopen) {
+ if (m_Mixer_fd >= 0)
+ closeMixerDevice(/* force = */ true);
+ else
+ return true;
+ }
+
+ if (m_Mixer_fd < 0)
+ m_Mixer_fd = open(m_MixerDeviceName.ascii(), O_RDONLY);
+
+ if (m_Mixer_fd < 0) {
+ logError(i18n("Cannot open mixer device %1").arg(m_MixerDeviceName));
+ } else {
+ m_PollingTimer.start(40);
+ }
+ return m_Mixer_fd >= 0;
+}
+
+
+bool OSSSoundDevice::closeMixerDevice(bool force)
+{
+ if ((!m_PlaybackStreamID.isValid() && !m_CaptureStreamID.isValid()) || force) {
+
+ if (m_DSP_fd < 0)
+ m_PollingTimer.stop();
+
+ if (m_Mixer_fd >= 0)
+ close (m_Mixer_fd);
+ m_Mixer_fd = -1;
+ }
+ return m_Mixer_fd < 0;
+}
+
+
+void OSSSoundDevice::getMixerChannels(int query, QStringList &retval, QMap<QString, int> &revmap) const
+{
+ retval.clear();
+ revmap.clear();
+
+ int fd = m_Mixer_fd;
+ if (fd < 0)
+ fd = open(m_MixerDeviceName.ascii(), O_RDONLY);
+
+ if (fd < 0) {
+ logError(i18n("OSSSoundDevice::getMixerChannels: Cannot open mixer device %1").arg(m_MixerDeviceName));
+ }
+
+ if (fd >= 0) {
+ int mask = 0;
+ if ( ioctl(fd, MIXER_READ(query), &mask) == 0 ) {
+ for (int i = 0; i < SOUND_MIXER_NRDEVICES; ++i) {
+ if (mask & (1 << i)) {
+ static const char *labels[] = SOUND_DEVICE_LABELS;
+ retval.append(i18n(labels[i]));
+ revmap.insert(i18n(labels[i]), i);
+ }
+ }
+ } else {
+ logError(i18n("OSSSoundDevice::getMixerChannels: Cannot read mixer device mask on device %1").arg(m_MixerDeviceName));
+ }
+ }
+ if (fd != m_Mixer_fd)
+ close(fd);
+}
+
+
+const QStringList &OSSSoundDevice::getPlaybackChannels() const
+{
+ return m_PlaybackChannels;
+}
+
+
+const QStringList &OSSSoundDevice::getCaptureChannels() const
+{
+ return m_CaptureChannels;
+}
+
+
+bool OSSSoundDevice::setPlaybackVolume(SoundStreamID id, float volume)
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ if (rint(100*volume) != rint(100*cfg.m_Volume)) {
+ cfg.m_Volume = writeMixerVolume(cfg.m_Channel, volume);
+ notifyPlaybackVolumeChanged(id, cfg.m_Volume);
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool OSSSoundDevice::setCaptureVolume(SoundStreamID id, float volume)
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ if (rint(100*volume) != rint(100*cfg.m_Volume)) {
+ cfg.m_Volume = writeMixerVolume(cfg.m_Channel, volume);
+ notifyCaptureVolumeChanged(id, cfg.m_Volume);
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool OSSSoundDevice::getPlaybackVolume(SoundStreamID id, float &volume) const
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ const SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ volume = cfg.m_Volume;
+ return true;
+ }
+ return false;
+}
+
+
+bool OSSSoundDevice::getCaptureVolume(SoundStreamID id, float &volume) const
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ const SoundStreamConfig &cfg = m_CaptureStreams[id];
+ volume = cfg.m_Volume;
+ return true;
+ }
+ return false;
+}
+
+
+void OSSSoundDevice::checkMixerVolume(SoundStreamID id)
+{
+ if (m_Mixer_fd >= 0 && id.isValid()) {
+
+ if (m_PassivePlaybackStreams.contains(id) || m_PlaybackStreamID == id) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ float v = readMixerVolume(cfg.m_Channel);
+ if (rint(100*cfg.m_Volume) != rint(100*v)) {
+ cfg.m_Volume = v;
+ notifyPlaybackVolumeChanged(id, v);
+ }
+ }
+
+ if (m_CaptureStreamID == id) {
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ float v = readMixerVolume(cfg.m_Channel);
+ if (rint(100*cfg.m_Volume) != rint(100*v)) {
+ cfg.m_Volume = v;
+ notifyCaptureVolumeChanged(id, v);
+ }
+ }
+ }
+}
+
+
+float OSSSoundDevice::readMixerVolume(int channel) const
+{
+ _lrvol tmpvol;
+ int err = ioctl(m_Mixer_fd, MIXER_READ(channel), &tmpvol);
+ if (err) {
+ logError("OSSSound::readMixerVolume: " +
+ i18n("error %1 while reading volume from %2")
+ .arg(QString().setNum(err))
+ .arg(m_MixerDeviceName));
+ tmpvol.l = tmpvol.r = 0;
+ }
+ return float(tmpvol.l) / 100.0;
+}
+
+
+float OSSSoundDevice::writeMixerVolume (int channel, float vol)
+{
+ if (vol > 1.0) vol = 1.0;
+ if (vol < 0) vol = 0.0;
+
+ const int divs = 100;
+ vol = rint(vol * divs) / float(divs);
+
+ if (m_Mixer_fd >= 0) {
+ _lrvol tmpvol;
+ tmpvol.r = tmpvol.l = (unsigned int)(rint(vol * divs));
+ int err = ioctl(m_Mixer_fd, MIXER_WRITE(channel), &tmpvol);
+ if (err != 0) {
+ logError("OSSSoundDevice::writeMixerVolume: " +
+ i18n("error %1 while setting volume to %2 on device %3")
+ .arg(QString().setNum(err))
+ .arg(QString().setNum(vol))
+ .arg(m_MixerDeviceName));
+ return -1;
+ }
+ }
+ return vol;
+}
+
+
+void OSSSoundDevice::selectCaptureChannel (int channel)
+{
+ int x = 1 << channel;
+ int err = ioctl(m_Mixer_fd, SOUND_MIXER_WRITE_RECSRC, &x);
+ if (err)
+ logError(i18n("Selecting recording source on device %1 failed with error code %2")
+ .arg(m_MixerDeviceName)
+ .arg(QString::number(err)));
+ _lrvol tmpvol;
+ err = ioctl(m_Mixer_fd, MIXER_READ(SOUND_MIXER_IGAIN), &tmpvol);
+ if (err)
+ logError(i18n("Reading igain volume on device %1 failed with error code %2")
+ .arg(m_MixerDeviceName)
+ .arg(QString::number(err)));
+ if (tmpvol.r == 0 && tmpvol.l == 0) {
+ tmpvol.r = tmpvol.l = 1;
+ err = ioctl(m_Mixer_fd, MIXER_WRITE(SOUND_MIXER_IGAIN), &tmpvol);
+ if (err)
+ logError(i18n("Setting igain volume on device %1 failed with error code %2")
+ .arg(m_MixerDeviceName)
+ .arg(QString::number(err)));
+ }
+}
+
+
+int OSSSoundDevice::getOSSFormat(const SoundFormat &f)
+{
+ if (f.m_SampleBits == 16) {
+ switch (2 * f.m_IsSigned + (f.m_Endianess == LITTLE_ENDIAN)) {
+ case 0: return AFMT_U16_BE;
+ case 1: return AFMT_U16_LE;
+ case 2: return AFMT_S16_BE;
+ case 3: return AFMT_S16_LE;
+ }
+ }
+ if (f.m_SampleBits == 8) {
+ switch (f.m_IsSigned) {
+ case 0: return AFMT_U8;
+ case 1: return AFMT_S8;
+ }
+ }
+ return 0;
+}
+
+
+void OSSSoundDevice::setBufferSize(int s)
+{
+ m_BufferSize = s;
+ m_PlaybackBuffer.resize(m_BufferSize);
+ m_CaptureBuffer.resize(m_BufferSize);
+}
+
+
+void OSSSoundDevice::enablePlayback(bool on)
+{
+ m_EnablePlayback = on;
+}
+
+
+void OSSSoundDevice::enableCapture(bool on)
+{
+ m_EnableCapture = on;
+}
+
+
+void OSSSoundDevice::setDSPDeviceName(const QString &s)
+{
+ m_DSPDeviceName = s;
+ SoundFormat f = m_DSPFormat;
+ if (m_DSP_fd >= 0)
+ openDSPDevice(f, /* reopen = */ true);
+}
+
+
+QString OSSSoundDevice::getSoundStreamClientDescription() const
+{
+ return i18n("OSS Sound Device %1").arg(PluginBase::name());
+}
+
+
+
+#include "oss-sound.moc"
diff --git a/kradio3/plugins/oss-sound/oss-sound.h b/kradio3/plugins/oss-sound/oss-sound.h
new file mode 100644
index 0000000..139ee64
--- /dev/null
+++ b/kradio3/plugins/oss-sound/oss-sound.h
@@ -0,0 +1,224 @@
+/***************************************************************************
+ oss-sound.h - description
+ -------------------
+ begin : Sun Mar 21 2004
+ copyright : (C) 2004 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KRADIO_OSS_SOUND_H
+#define _KRADIO_OSS_SOUND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/ringbuffer.h"
+#include "../../src/include/plugins.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+#include <qobject.h>
+#include <qtimer.h>
+
+enum DUPLEX_MODE { DUPLEX_UNKNOWN, DUPLEX_FULL, DUPLEX_HALF };
+
+
+struct SoundStreamConfig
+{
+ SoundStreamConfig()
+ : m_ActiveMode(false),
+ m_Channel(-1),
+ m_Volume(-1)
+ {}
+
+ SoundStreamConfig(int _channel, bool active_mode = true)
+ : m_ActiveMode(active_mode),
+ m_Channel(_channel),
+ m_Volume(-1)
+ {}
+
+ SoundStreamConfig(const SoundStreamConfig &c)
+ : m_ActiveMode(c.m_ActiveMode),
+ m_Channel(c.m_Channel),
+ m_Volume(c.m_Volume)
+ {}
+
+ bool m_ActiveMode;
+ int m_Channel;
+ float m_Volume;
+};
+
+
+class OSSSoundDevice : public QObject,
+ public PluginBase,
+ public ISoundStreamClient
+{
+Q_OBJECT
+
+public:
+ OSSSoundDevice (const QString &name);
+ virtual ~OSSSoundDevice ();
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual QString pluginClassName() const { return "OSSSoundDevice"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // ISoundStreamClient: direct device access
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+ bool preparePlayback(SoundStreamID id, const QString &channel, bool active_mode, bool start_immediately);
+ bool prepareCapture(SoundStreamID id, const QString &channel);
+ bool releasePlayback(SoundStreamID id);
+ bool releaseCapture(SoundStreamID id);
+
+ANSWERS:
+ bool supportsPlayback() const;
+ bool supportsCapture() const;
+
+ QString getSoundStreamClientDescription() const;
+
+ // ISoundStreamClient: mixer access
+
+protected:
+ void getMixerChannels(int query_playback_or_rec_mask, QStringList &retval, QMap<QString, int> &revmap) const;
+
+ANSWERS:
+ const QStringList &getPlaybackChannels() const;
+ const QStringList &getCaptureChannels() const;
+
+RECEIVERS:
+ bool setPlaybackVolume(SoundStreamID id, float volume);
+ bool setCaptureVolume(SoundStreamID id, float volume);
+ bool getPlaybackVolume(SoundStreamID id, float &volume) const;
+ bool getCaptureVolume(SoundStreamID id, float &volume) const;
+
+ // ISoundStreamClient: generic broadcasts
+
+RECEIVERS:
+ bool startPlayback(SoundStreamID id);
+ bool pausePlayback(SoundStreamID id);
+ bool stopPlayback(SoundStreamID id);
+ bool isPlaybackRunning(SoundStreamID id, bool &b) const;
+
+ bool startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format);
+ bool stopCapture(SoundStreamID id);
+ bool isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const;
+
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID);
+
+ bool noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+ );
+
+
+ // Config Access
+
+ int getBufferSize() const { return m_BufferSize; }
+ bool isPlaybackEnabled() const { return m_EnablePlayback; }
+ bool isCaptureEnabled() const { return m_EnableCapture; }
+ const QString &getDSPDeviceName() const { return m_DSPDeviceName; }
+ const QString &getMixerDeviceName() const { return m_MixerDeviceName; }
+
+ void setBufferSize(int s);
+ void enablePlayback(bool on);
+ void enableCapture(bool on);
+ void setDSPDeviceName(const QString &s);
+ void setMixerDeviceName(const QString &dev_name);
+
+ // own functions
+
+ static int getOSSFormat(const SoundFormat &f);
+
+protected slots:
+
+ void slotPoll();
+
+signals:
+
+ void sigUpdateConfig();
+
+protected:
+
+ bool openDSPDevice(const SoundFormat &format, bool reopen = false);
+ bool closeDSPDevice(bool force = false);
+
+ bool openMixerDevice(bool reopen = false);
+ bool closeMixerDevice(bool force = false);
+
+ void checkMixerVolume(SoundStreamID id);
+ float readMixerVolume(int channel) const;
+ float writeMixerVolume(int channel, float vol);
+
+ void selectCaptureChannel (int channel);
+
+ QString m_DSPDeviceName,
+ m_MixerDeviceName;
+ int m_DSP_fd,
+ m_Mixer_fd;
+ DUPLEX_MODE m_DuplexMode;
+ SoundFormat m_DSPFormat;
+
+ QStringList m_PlaybackChannels,
+ m_CaptureChannels;
+ QMap<QString, int> m_revPlaybackChannels,
+ m_revCaptureChannels;
+
+ QMap<SoundStreamID, SoundStreamConfig>
+ m_PlaybackStreams,
+ m_CaptureStreams;
+
+ QValueList<SoundStreamID>
+ m_PassivePlaybackStreams;
+ SoundStreamID m_PlaybackStreamID,
+ m_CaptureStreamID;
+
+ size_t m_BufferSize;
+ RingBuffer m_PlaybackBuffer,
+ m_CaptureBuffer;
+
+ unsigned m_CaptureRequestCounter;
+ Q_UINT64 m_CapturePos;
+ time_t m_CaptureStartTime;
+
+
+ size_t //m_PlaybackSkipCount,
+ m_CaptureSkipCount;
+
+ bool m_EnablePlayback,
+ m_EnableCapture;
+
+ QTimer m_PollingTimer;
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/oss-sound/po/Makefile.am b/kradio3/plugins/oss-sound/po/Makefile.am
new file mode 100644
index 0000000..d6cceda
--- /dev/null
+++ b/kradio3/plugins/oss-sound/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-oss-sound
+POFILES = AUTO
diff --git a/kradio3/plugins/oss-sound/po/de.po b/kradio3/plugins/oss-sound/po/de.po
new file mode 100644
index 0000000..3ff8fdc
--- /dev/null
+++ b/kradio3/plugins/oss-sound/po/de.po
@@ -0,0 +1,200 @@
+# translation of de.po to
+# translation of kradio-oss-sound.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:41+0100\n"
+"PO-Revision-Date: 2006-11-12 18:24+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file oss-sound-configuration-ui.ui line 27
+#: rc.cpp:3 rc.cpp:27 oss-sound-configuration-ui.cpp:106
+#, no-c-format
+msgid "Devices"
+msgstr "Geräte"
+
+#. i18n: file oss-sound-configuration-ui.ui line 51
+#: rc.cpp:6 rc.cpp:30 oss-sound-configuration-ui.cpp:107
+#, no-c-format
+msgid "PCM Device"
+msgstr "Gerät"
+
+#. i18n: file oss-sound-configuration-ui.ui line 59
+#: rc.cpp:9 rc.cpp:33 oss-sound-configuration-ui.cpp:108
+#, no-c-format
+msgid "Mixer Device"
+msgstr "Mixer Gerätedatei"
+
+#. i18n: file oss-sound-configuration-ui.ui line 67
+#: rc.cpp:12 rc.cpp:36 oss-sound-configuration-ui.cpp:109
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Puffergröße"
+
+#. i18n: file oss-sound-configuration-ui.ui line 75
+#: rc.cpp:15 rc.cpp:39 oss-sound-configuration-ui.cpp:110
+#, no-c-format
+msgid " kB"
+msgstr " kB"
+
+#. i18n: file oss-sound-configuration-ui.ui line 91
+#: rc.cpp:18 rc.cpp:42 oss-sound-configuration-ui.cpp:111
+#, no-c-format
+msgid "Extended Options"
+msgstr "Erweiterte Optionen"
+
+#. i18n: file oss-sound-configuration-ui.ui line 105
+#: rc.cpp:21 rc.cpp:45 oss-sound-configuration-ui.cpp:112
+#, no-c-format
+msgid "Disable Playback"
+msgstr "Wiedergabe abschalten"
+
+#. i18n: file oss-sound-configuration-ui.ui line 113
+#: rc.cpp:24 rc.cpp:48 oss-sound-configuration-ui.cpp:113
+#, no-c-format
+msgid "Disable Capture"
+msgstr "Aufnahme abschalten"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: oss-sound.cpp:38
+msgid "Open Sound System (OSS) Support"
+msgstr "Unterstützung für das Open Sound System (OSS)"
+
+#: oss-sound.cpp:46
+msgid "KRadio OSS Sound Plugin"
+msgstr "KRadio Plugin für das Open Sound System (OSS)"
+
+#: oss-sound.cpp:172
+msgid "OSS Sound"
+msgstr "OSS Sound"
+
+#: oss-sound.cpp:173
+msgid "OSS Sound Device Options"
+msgstr "Geräteoptionen für den OSS Sound"
+
+#: oss-sound.cpp:507
+msgid "OSS device %1: No data to record"
+msgstr "OSS Gerät %1: Keine Daten zum Aufnehmen"
+
+#: oss-sound.cpp:517
+msgid "internal stream, not stored (%1)"
+msgstr "interner, nicht aufgezeichneter Datenstrom (%1)"
+
+#: oss-sound.cpp:549
+msgid "Error %1 while handling OSS device %2"
+msgstr "Fehler %1 beim Behandeln vom OSS-Gerät %2"
+
+#: oss-sound.cpp:593 oss-sound.cpp:619
+msgid "Cannot open DSP device %1"
+msgstr "Die Audio-Gerätedatei %1 kann nicht geöffnet werden"
+
+#: oss-sound.cpp:599
+msgid "Cannot read DSP capabilities for %1"
+msgstr "Kann die Fähigkeiten des Gerätes %1 nicht lesen."
+
+#: oss-sound.cpp:626
+msgid "Cannot set DSP sample format for %1"
+msgstr "Kann das Abtastformat für %1 nicht schreiben"
+
+#: oss-sound.cpp:631
+msgid "Cannot set number of channels for %1"
+msgstr "Kann die Anzahl der Kanäle für %1 nicht festlegen"
+
+#: oss-sound.cpp:636
+msgid "Cannot set sampling rate for %1"
+msgstr "Kann die Abtastrate für %1 nicht setzen"
+
+#: oss-sound.cpp:638
+msgid "Asking for %1 Hz but %2 uses %3 Hz"
+msgstr ""
+"%1 Hz sollen als Abtastrate verwendet werden, kann aber nur %3 Hz für das "
+"Gerät %2 verwendens"
+
+#: oss-sound.cpp:648
+msgid "Cannot set stereo mode for %1"
+msgstr "Kann den Stereo-Modus für %1 nicht setzen"
+
+#: oss-sound.cpp:653
+msgid "Cannot set sample size for %1"
+msgstr "Kann das Quantisierung-Format für %1 nicht setzen"
+
+#: oss-sound.cpp:662
+msgid "Cannot set buffers for %1"
+msgstr "Kann die Puffer für %1 nicht einstellen"
+
+#: oss-sound.cpp:667
+msgid "Cannot read buffer size for %1"
+msgstr "Kann die Puffergröße für %1 nicht lesen"
+
+#: oss-sound.cpp:669
+msgid "%1 uses buffer blocks of %2 bytes"
+msgstr "Gerät %1 verwendet Pufferblöcke von %2 Bytes"
+
+#: oss-sound.cpp:672
+msgid "adjusted own buffer size to %1 bytes"
+msgstr "Die interne Puffergröße wurde auf %1 bytes angepasst"
+
+#: oss-sound.cpp:724
+msgid "Cannot open mixer device %1"
+msgstr "Die Mixergerätedatei %1 kann nicht geöffnet werden"
+
+#: oss-sound.cpp:757
+msgid "OSSSoundDevice::getMixerChannels: Cannot open mixer device %1"
+msgstr "OSSSoundDevice::getMixerChannels: Kann den Mixer %1 nicht öffnen"
+
+#: oss-sound.cpp:771
+msgid ""
+"OSSSoundDevice::getMixerChannels: Cannot read mixer device mask on device %1"
+msgstr ""
+"OSSSoundDevice::getMixerChannels: Kann die Gerätemaske des Mixers %1 nicht "
+"lesen"
+
+#: oss-sound.cpp:876
+msgid "error %1 while reading volume from %2"
+msgstr "Fehler %1 beim Lesen der Lautstärke von %2"
+
+#: oss-sound.cpp:899
+msgid "error %1 while setting volume to %2 on device %3"
+msgstr "Fehler %1 beim setzen der Lautstärke %2 auf dem Gerät %3"
+
+#: oss-sound.cpp:915
+msgid "Selecting recording source on device %1 failed with error code %2"
+msgstr ""
+"Das Auswählen der Aufnahmequelle auf dem Gerät %1 schlug mit Fehlercode %2 "
+"fehl"
+
+#: oss-sound.cpp:921
+msgid "Reading igain volume on device %1 failed with error code %2"
+msgstr ""
+"Das Lesen der Aufnahmeverstärkung vom Geräte %1 schlug fehl mit dem "
+"Fehlercode %2"
+
+#: oss-sound.cpp:928
+msgid "Setting igain volume on device %1 failed with error code %2"
+msgstr ""
+"Das Schreiben der Aufnahmeverstärkung vom Geräte %1 schlug fehl mit dem "
+"Fehlercode %2"
+
+#: oss-sound.cpp:986
+msgid "OSS Sound Device %1"
+msgstr "OSS Sound Gerät %1"
diff --git a/kradio3/plugins/oss-sound/po/ru.po b/kradio3/plugins/oss-sound/po/ru.po
new file mode 100644
index 0000000..d8f18db
--- /dev/null
+++ b/kradio3/plugins/oss-sound/po/ru.po
@@ -0,0 +1,193 @@
+# translation of ru.po to
+# translation of kradio-oss-sound.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:20+0100\n"
+"PO-Revision-Date: 2006-11-08 12:45+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file oss-sound-configuration-ui.ui line 27
+#: rc.cpp:3 rc.cpp:27 oss-sound-configuration-ui.cpp:106
+#, no-c-format
+msgid "Devices"
+msgstr "Устройства"
+
+#. i18n: file oss-sound-configuration-ui.ui line 51
+#: rc.cpp:6 rc.cpp:30 oss-sound-configuration-ui.cpp:107
+#, no-c-format
+msgid "PCM Device"
+msgstr "Устройство PCM"
+
+#. i18n: file oss-sound-configuration-ui.ui line 59
+#: rc.cpp:9 rc.cpp:33 oss-sound-configuration-ui.cpp:108
+#, no-c-format
+msgid "Mixer Device"
+msgstr "Устройство микшера"
+
+#. i18n: file oss-sound-configuration-ui.ui line 67
+#: rc.cpp:12 rc.cpp:36 oss-sound-configuration-ui.cpp:109
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Размер буфера"
+
+#. i18n: file oss-sound-configuration-ui.ui line 75
+#: rc.cpp:15 rc.cpp:39 oss-sound-configuration-ui.cpp:110
+#, no-c-format
+msgid " kB"
+msgstr " кБ"
+
+#. i18n: file oss-sound-configuration-ui.ui line 91
+#: rc.cpp:18 rc.cpp:42 oss-sound-configuration-ui.cpp:111
+#, no-c-format
+msgid "Extended Options"
+msgstr "Дополнительные параметры"
+
+#. i18n: file oss-sound-configuration-ui.ui line 105
+#: rc.cpp:21 rc.cpp:45 oss-sound-configuration-ui.cpp:112
+#, no-c-format
+msgid "Disable Playback"
+msgstr "Запретить &воспроизведение"
+
+#. i18n: file oss-sound-configuration-ui.ui line 113
+#: rc.cpp:24 rc.cpp:48 oss-sound-configuration-ui.cpp:113
+#, no-c-format
+msgid "Disable Capture"
+msgstr "Запретить &запись"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: oss-sound.cpp:38
+msgid "Open Sound System (OSS) Support"
+msgstr "Поддержка Открытой звуковой системы (OSS)"
+
+#: oss-sound.cpp:46
+msgid "KRadio OSS Sound Plugin"
+msgstr "Модуль OSS для KRadio"
+
+#: oss-sound.cpp:172
+msgid "OSS Sound"
+msgstr "OSS"
+
+#: oss-sound.cpp:173
+msgid "OSS Sound Device Options"
+msgstr "Параметры звука для драйвера OSS"
+
+#: oss-sound.cpp:507
+msgid "OSS device %1: No data to record"
+msgstr "Устройство OSS %1: для записи нет данных"
+
+#: oss-sound.cpp:517
+msgid "internal stream, not stored (%1)"
+msgstr ""
+
+#: oss-sound.cpp:549
+msgid "Error %1 while handling OSS device %2"
+msgstr "Ошибка %1 при работе с устройством OSS %2."
+
+#: oss-sound.cpp:593 oss-sound.cpp:619
+msgid "Cannot open DSP device %1"
+msgstr "Не могу открыть устройство звуковой платы %1"
+
+#: oss-sound.cpp:599
+msgid "Cannot read DSP capabilities for %1"
+msgstr "Не могу узнать возможности звуковой платы %1"
+
+#: oss-sound.cpp:626
+msgid "Cannot set DSP sample format for %1"
+msgstr "Не могу установить формат данных для звуковой платы %1"
+
+#: oss-sound.cpp:631
+msgid "Cannot set number of channels for %1"
+msgstr "Не могу установить число каналов для звуковой платы %1"
+
+#: oss-sound.cpp:636
+msgid "Cannot set sampling rate for %1"
+msgstr "Не могу установить частоту дискретизации для звуковой платы %1"
+
+#: oss-sound.cpp:638
+msgid "Asking for %1 Hz but %2 uses %3 Hz"
+msgstr "Был дан запрос на %1 Гц, однако %2 использует %3 Гц."
+
+#: oss-sound.cpp:648
+msgid "Cannot set stereo mode for %1"
+msgstr "Не могу установить стерео режим для звуковой платы %1"
+
+#: oss-sound.cpp:653
+msgid "Cannot set sample size for %1"
+msgstr "Не могу установить размер элемента выборки для звуковой платы %1"
+
+#: oss-sound.cpp:662
+msgid "Cannot set buffers for %1"
+msgstr "Не могу установить буферы для звуковой платы %1"
+
+#: oss-sound.cpp:667
+msgid "Cannot read buffer size for %1"
+msgstr "Не могу узнать размер буфера звуковой платы %1"
+
+#: oss-sound.cpp:669
+msgid "%1 uses buffer blocks of %2 bytes"
+msgstr "%1 использует блоки буфера по %2 байт"
+
+#: oss-sound.cpp:672
+msgid "adjusted own buffer size to %1 bytes"
+msgstr "Размер собственного буфера установлен %1 байт."
+
+#: oss-sound.cpp:724
+msgid "Cannot open mixer device %1"
+msgstr "Не могу открыть устройство микшера %1"
+
+#: oss-sound.cpp:757
+msgid "OSSSoundDevice::getMixerChannels: Cannot open mixer device %1"
+msgstr ""
+"OSSSoundDevice::getMixerChannels: Не могу открыть устройство микшера %1"
+
+#: oss-sound.cpp:771
+msgid ""
+"OSSSoundDevice::getMixerChannels: Cannot read mixer device mask on device %1"
+msgstr ""
+"OSSSoundDevice::getMixerChannels: не могу прочесть маску устройства микшера "
+"для устройства %1"
+
+#: oss-sound.cpp:876
+msgid "error %1 while reading volume from %2"
+msgstr "Ошибка %1 при считывании громкости с %2."
+
+#: oss-sound.cpp:899
+msgid "error %1 while setting volume to %2 on device %3"
+msgstr "Ошибка %1 при установке громкости %2 на устройстве %3."
+
+#: oss-sound.cpp:915
+msgid "Selecting recording source on device %1 failed with error code %2"
+msgstr "Выбор источника записи на устройстве %1 не удался (код ошибки %2)"
+
+#: oss-sound.cpp:921
+msgid "Reading igain volume on device %1 failed with error code %2"
+msgstr "Считывание громкости записи с устройства %1 не удалось (код ошибки %2)"
+
+#: oss-sound.cpp:928
+msgid "Setting igain volume on device %1 failed with error code %2"
+msgstr "Установка громкости записи на устройстве %1 не удалась (код ошибки %2)"
+
+#: oss-sound.cpp:986
+msgid "OSS Sound Device %1"
+msgstr "Устройство OSS: %1"
diff --git a/kradio3/plugins/radio/Makefile.am b/kradio3/plugins/radio/Makefile.am
new file mode 100644
index 0000000..2481b58
--- /dev/null
+++ b/kradio3/plugins/radio/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po .
+
+INCLUDES = -I$(top_builddir)/kradio3/src -I$(top_srcdir)/kradio3 $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libradio.la
+libradio_la_SOURCES = radio-configuration.cpp radio-configuration-ui.ui \
+ radio.cpp
+libradio_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = radio-configuration.h radio.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-radio.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-radio.pot
diff --git a/kradio3/plugins/radio/po/Makefile.am b/kradio3/plugins/radio/po/Makefile.am
new file mode 100644
index 0000000..9fedd9c
--- /dev/null
+++ b/kradio3/plugins/radio/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-radio
+POFILES = AUTO
diff --git a/kradio3/plugins/radio/po/de.po b/kradio3/plugins/radio/po/de.po
new file mode 100644
index 0000000..5f7553d
--- /dev/null
+++ b/kradio3/plugins/radio/po/de.po
@@ -0,0 +1,185 @@
+# translation of de.po to
+# translation of kradio-radio.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-06 01:18+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file radio-configuration-ui.ui line 28
+#: rc.cpp:3 rc.cpp:68 radio-configuration-ui.cpp:325
+#, no-c-format
+msgid "Station &Presets"
+msgstr "&Voreingestellte Sender"
+
+#. i18n: file radio-configuration-ui.ui line 53
+#: rc.cpp:6 rc.cpp:71 radio-configuration-ui.cpp:310
+#, no-c-format
+msgid "Stations"
+msgstr "Sender"
+
+#. i18n: file radio-configuration-ui.ui line 179
+#: rc.cpp:13 rc.cpp:78 radio-configuration-ui.cpp:315
+#, no-c-format
+msgid "&Search Stations"
+msgstr "&Sendersuche"
+
+#. i18n: file radio-configuration-ui.ui line 198
+#: rc.cpp:16 rc.cpp:81 radio-configuration-ui.cpp:316
+#, no-c-format
+msgid "Load"
+msgstr "Öffnen"
+
+#. i18n: file radio-configuration-ui.ui line 263
+#: rc.cpp:22 rc.cpp:87 radio-configuration-ui.cpp:318
+#, no-c-format
+msgid "Name"
+msgstr "Name"
+
+#. i18n: file radio-configuration-ui.ui line 294
+#: rc.cpp:25 rc.cpp:90 radio-configuration-ui.cpp:319
+#, no-c-format
+msgid "Short Name"
+msgstr "Kurzname"
+
+#. i18n: file radio-configuration-ui.ui line 325
+#: rc.cpp:28 rc.cpp:93 radio-configuration-ui.cpp:320
+#, no-c-format
+msgid "Pixmap File"
+msgstr "Bilddatei"
+
+#. i18n: file radio-configuration-ui.ui line 457
+#: rc.cpp:32 rc.cpp:97 radio-configuration-ui.cpp:322
+#, no-c-format
+msgid " %"
+msgstr " %"
+
+#. i18n: file radio-configuration-ui.ui line 471
+#: rc.cpp:35 rc.cpp:100 radio-configuration-ui.cpp:323
+#, no-c-format
+msgid "Volume Preset"
+msgstr "Lautstärke"
+
+#. i18n: file radio-configuration-ui.ui line 508
+#: rc.cpp:38 rc.cpp:103 radio-configuration-ui.cpp:324
+#, no-c-format
+msgid "Personal Preset File"
+msgstr "Persönliche Senderdatei"
+
+#. i18n: file radio-configuration-ui.ui line 564
+#: rc.cpp:44 rc.cpp:109 radio-configuration-ui.cpp:326
+#, no-c-format
+msgid "City"
+msgstr "Stadt"
+
+#. i18n: file radio-configuration-ui.ui line 577
+#: rc.cpp:47 rc.cpp:112 radio-configuration-ui.cpp:327
+#, no-c-format
+msgid "Country"
+msgstr "Land"
+
+#. i18n: file radio-configuration-ui.ui line 617
+#: rc.cpp:50 rc.cpp:115 radio-configuration-ui.cpp:328
+#, no-c-format
+msgid "&Now"
+msgstr "&Jetzt"
+
+#. i18n: file radio-configuration-ui.ui line 627
+#: rc.cpp:53 rc.cpp:118 radio-configuration-ui.cpp:329
+#, no-c-format
+msgid "Comment"
+msgstr "Kommentar"
+
+#. i18n: file radio-configuration-ui.ui line 640
+#: rc.cpp:56 rc.cpp:121 radio-configuration-ui.cpp:330
+#, no-c-format
+msgid "Media"
+msgstr "Medium"
+
+#. i18n: file radio-configuration-ui.ui line 648
+#: rc.cpp:59 rc.cpp:124 radio-configuration-ui.cpp:331
+#, no-c-format
+msgid "Maintainer"
+msgstr "Maintainer"
+
+#. i18n: file radio-configuration-ui.ui line 661
+#: rc.cpp:62 rc.cpp:127 radio-configuration-ui.cpp:332
+#, no-c-format
+msgid "Last Change"
+msgstr "Letzte Änderung"
+
+#. i18n: file radio-configuration-ui.ui line 698
+#: rc.cpp:65 rc.cpp:130 radio-configuration-ui.cpp:333
+#, no-c-format
+msgid ""
+"<p align=\"center\">Click on the link below to contribute this station "
+"preset file to the kradio project.</p>"
+msgstr ""
+"<p align=\"center\">Klicke auf den folgenden Link um mit deinen "
+"Senderinformationen zum KRadio-Projekt beizutragen.</p>"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "witte@kawo1.rwth-aachen.de"
+
+#: radio-configuration.cpp:350
+msgid "Image Selection"
+msgstr "Symbolauswahl"
+
+#: radio-configuration.cpp:355
+msgid "ignoring non-local image"
+msgstr "Ignoriere nicht-lokale Symbole"
+
+#: radio-configuration.cpp:450 radio-configuration.cpp:470
+msgid "KRadio Preset Files"
+msgstr "Senderdateien für KRadio"
+
+#: radio-configuration.cpp:452 radio-configuration.cpp:472
+msgid "Preset File Selection"
+msgstr "Auswahl der Senderdatei"
+
+#: radio-configuration.cpp:455
+msgid "Select Preset File"
+msgstr "Wählen Sie eine Senderdatei aus"
+
+#: radio-configuration.cpp:475
+msgid "Store Preset File"
+msgstr "Speichern der Senderdatei"
+
+#: radio.cpp:34
+msgid "Central Radio Device Multiplexer"
+msgstr "Zentraler Radio-Multiplexer"
+
+#: radio.cpp:39
+msgid "Radio Multiplexer Plugin"
+msgstr "Plugin für den Radio-Gerätemultiplexer"
+
+#: radio.cpp:116
+msgid "Radio Stations"
+msgstr "Radiosender"
+
+#: radio.cpp:117
+msgid "Setup Radio Stations"
+msgstr "Einstellung der Radiosender"
+
+#: radio.cpp:351
+msgid "unknown"
+msgstr "unbekannt"
diff --git a/kradio3/plugins/radio/po/ru.po b/kradio3/plugins/radio/po/ru.po
new file mode 100644
index 0000000..3a403db
--- /dev/null
+++ b/kradio3/plugins/radio/po/ru.po
@@ -0,0 +1,185 @@
+# translation of ru.po to
+# translation of kradio-radio.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-08 13:00+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file radio-configuration-ui.ui line 28
+#: rc.cpp:3 rc.cpp:68 radio-configuration-ui.cpp:325
+#, no-c-format
+msgid "Station &Presets"
+msgstr "Параметры &радиостанций"
+
+#. i18n: file radio-configuration-ui.ui line 53
+#: rc.cpp:6 rc.cpp:71 radio-configuration-ui.cpp:310
+#, no-c-format
+msgid "Stations"
+msgstr "Список"
+
+#. i18n: file radio-configuration-ui.ui line 179
+#: rc.cpp:13 rc.cpp:78 radio-configuration-ui.cpp:315
+#, no-c-format
+msgid "&Search Stations"
+msgstr "&Поиск"
+
+#. i18n: file radio-configuration-ui.ui line 198
+#: rc.cpp:16 rc.cpp:81 radio-configuration-ui.cpp:316
+#, no-c-format
+msgid "Load"
+msgstr "Из файла"
+
+#. i18n: file radio-configuration-ui.ui line 263
+#: rc.cpp:22 rc.cpp:87 radio-configuration-ui.cpp:318
+#, no-c-format
+msgid "Name"
+msgstr "Название"
+
+#. i18n: file radio-configuration-ui.ui line 294
+#: rc.cpp:25 rc.cpp:90 radio-configuration-ui.cpp:319
+#, no-c-format
+msgid "Short Name"
+msgstr "Сокращённое название"
+
+#. i18n: file radio-configuration-ui.ui line 325
+#: rc.cpp:28 rc.cpp:93 radio-configuration-ui.cpp:320
+#, no-c-format
+msgid "Pixmap File"
+msgstr "Пиктограмма"
+
+#. i18n: file radio-configuration-ui.ui line 457
+#: rc.cpp:32 rc.cpp:97 radio-configuration-ui.cpp:322
+#, no-c-format
+msgid " %"
+msgstr " %"
+
+#. i18n: file radio-configuration-ui.ui line 471
+#: rc.cpp:35 rc.cpp:100 radio-configuration-ui.cpp:323
+#, no-c-format
+msgid "Volume Preset"
+msgstr "Установить громкость (-1=не менять)"
+
+#. i18n: file radio-configuration-ui.ui line 508
+#: rc.cpp:38 rc.cpp:103 radio-configuration-ui.cpp:324
+#, no-c-format
+msgid "Personal Preset File"
+msgstr "Пользовательский файл настроек"
+
+#. i18n: file radio-configuration-ui.ui line 564
+#: rc.cpp:44 rc.cpp:109 radio-configuration-ui.cpp:326
+#, no-c-format
+msgid "City"
+msgstr "Город"
+
+#. i18n: file radio-configuration-ui.ui line 577
+#: rc.cpp:47 rc.cpp:112 radio-configuration-ui.cpp:327
+#, no-c-format
+msgid "Country"
+msgstr "Страна"
+
+#. i18n: file radio-configuration-ui.ui line 617
+#: rc.cpp:50 rc.cpp:115 radio-configuration-ui.cpp:328
+#, no-c-format
+msgid "&Now"
+msgstr "&Текущее время"
+
+#. i18n: file radio-configuration-ui.ui line 627
+#: rc.cpp:53 rc.cpp:118 radio-configuration-ui.cpp:329
+#, no-c-format
+msgid "Comment"
+msgstr "Описание"
+
+#. i18n: file radio-configuration-ui.ui line 640
+#: rc.cpp:56 rc.cpp:121 radio-configuration-ui.cpp:330
+#, no-c-format
+msgid "Media"
+msgstr "Носитель"
+
+#. i18n: file radio-configuration-ui.ui line 648
+#: rc.cpp:59 rc.cpp:124 radio-configuration-ui.cpp:331
+#, no-c-format
+msgid "Maintainer"
+msgstr "Автор"
+
+#. i18n: file radio-configuration-ui.ui line 661
+#: rc.cpp:62 rc.cpp:127 radio-configuration-ui.cpp:332
+#, fuzzy, no-c-format
+msgid "Last Change"
+msgstr "Последнее изменение"
+
+#. i18n: file radio-configuration-ui.ui line 698
+#: rc.cpp:65 rc.cpp:130 radio-configuration-ui.cpp:333
+#, no-c-format
+msgid ""
+"<p align=\"center\">Click on the link below to contribute this station "
+"preset file to the kradio project.</p>"
+msgstr ""
+"<p align=\"center\"> Чтобы добавить этот файл в проект KRadio, щёлкните по "
+"ссылке ниже</p>"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: radio-configuration.cpp:350
+msgid "Image Selection"
+msgstr "Выбор картинки"
+
+#: radio-configuration.cpp:355
+msgid "ignoring non-local image"
+msgstr "Пропускать не локальные файлы"
+
+#: radio-configuration.cpp:450 radio-configuration.cpp:470
+msgid "KRadio Preset Files"
+msgstr "Файлы KRadio"
+
+#: radio-configuration.cpp:452 radio-configuration.cpp:472
+msgid "Preset File Selection"
+msgstr "Выбор файла радиостанций"
+
+#: radio-configuration.cpp:455
+msgid "Select Preset File"
+msgstr "Выбор файла радиостанций"
+
+#: radio-configuration.cpp:475
+msgid "Store Preset File"
+msgstr "Сохранить файл радиостанций"
+
+#: radio.cpp:34
+msgid "Central Radio Device Multiplexer"
+msgstr "Главный мультиплексор устройства радио"
+
+#: radio.cpp:39
+msgid "Radio Multiplexer Plugin"
+msgstr "Модуль мультиплексирования для KRadio"
+
+#: radio.cpp:116
+msgid "Radio Stations"
+msgstr "Радиостанции"
+
+#: radio.cpp:117
+msgid "Setup Radio Stations"
+msgstr "Настройка радиостанции"
+
+#: radio.cpp:351
+msgid "unknown"
+msgstr "низвестно"
diff --git a/kradio3/plugins/radio/radio-configuration-ui.ui b/kradio3/plugins/radio/radio-configuration-ui.ui
new file mode 100644
index 0000000..eee95e9
--- /dev/null
+++ b/kradio3/plugins/radio/radio-configuration-ui.ui
@@ -0,0 +1,774 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>RadioConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>RadioConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>490</width>
+ <height>348</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget3</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>stations</cstring>
+ </property>
+ <attribute name="title">
+ <string>Station &amp;Presets</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout32</cstring>
+ </property>
+ <property name="margin" stdset="0">
+ <number>6</number>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelStationList</cstring>
+ </property>
+ <property name="text">
+ <string>Stations</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout22</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="RadioStationListView">
+ <property name="name">
+ <cstring>listStations</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonNewStation</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"filenew2"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonDeleteStation</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"editdelete"</iconset>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonStationUp</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"1uparrow"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonStationDown</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"1downarrow"</iconset>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout21</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonSearchStations</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Search Stations</string>
+ </property>
+ <property name="iconSet">
+ <iconset>"find"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonLoadPresets</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Load</string>
+ </property>
+ <property name="iconSet">
+ <iconset>"fileopen"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonStorePresets</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Save As</string>
+ </property>
+ <property name="iconSet">
+ <iconset>"filesaveas"</iconset>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout18</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QWidgetStack">
+ <property name="name">
+ <cstring>stackStationEdit</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>page</cstring>
+ </property>
+ <attribute name="id">
+ <number>0</number>
+ </attribute>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelStationName</cstring>
+ </property>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>editStationName</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout32</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelStationShortName</cstring>
+ </property>
+ <property name="text">
+ <string>Short Name</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>editStationShortName</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelPixmapFile</cstring>
+ </property>
+ <property name="text">
+ <string>Pixmap File</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>editPixmapFile</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonSelectPixmapFile</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"fileopen"</iconset>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>pixmapStation</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>10</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>editVolumePreset</cstring>
+ </property>
+ <property name="suffix">
+ <string> %</string>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelVolumePreset</cstring>
+ </property>
+ <property name="text">
+ <string>Volume Preset</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout25</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>editLabelPresetFile</cstring>
+ </property>
+ <property name="text">
+ <string>Personal Preset File</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>editPresetFile</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>About</cstring>
+ </property>
+ <attribute name="title">
+ <string>A&amp;bout</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <spacer row="5" column="1">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>layout21</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>labelCity</cstring>
+ </property>
+ <property name="text">
+ <string>City</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>editCountry</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>labelCountry</cstring>
+ </property>
+ <property name="text">
+ <string>Country</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QDateTimeEdit">
+ <property name="name">
+ <cstring>editLastChange</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonLastChangeNow</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Now</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>labelComment</cstring>
+ </property>
+ <property name="text">
+ <string>Comment</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="5" column="1">
+ <property name="name">
+ <cstring>editComment</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>labelMedia</cstring>
+ </property>
+ <property name="text">
+ <string>Media</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelMaintainer</cstring>
+ </property>
+ <property name="text">
+ <string>Maintainer</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>editCity</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>labelLastChange</cstring>
+ </property>
+ <property name="text">
+ <string>Last Change</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>editMaintainer</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>editMedia</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer7_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Click on the link below to contribute this station preset file to the kradio project.&lt;/p&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="KURLLabel" row="4" column="1">
+ <property name="name">
+ <cstring>mailLabel</cstring>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>RadioStationListView</class>
+ <header location="local">src/include/radiostation-listview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="2782">789c8dd4df53e2481007f077ff0aca7eb3ae7a4948425257f78080a2828baebbea5eddc32493c80f110414f1eafef7eb7437dcdd9cd95a478afad47ca733193af97454bb1b0e6a479f0e566bb31e67b56c6496b523fb329b6d7fffe3b73f0f0e7dbf46ff5e3dacf987bf1c1c5ead6b59ed72fe9497800b02d4f9af34cefe6be83b1e3879ebb8e5b8edb8703c743c760c8e73c7a9e389e347c799733fe7cefc83e39163e378eaf8461d68fd253b26c73c1faa637550daab9783f3bc7fbf5e0e9eafab03f57776e2677ec2fe52ba9134e2061b36e2a0ae7e2e1d78413df038ff591d8881cf3730411c18f6bc74e88761c8cd02a84ec4f8956dc8923f565b319e958efcd046b2fe451c8562ecb14d642359cfe7dd6c34bd6683e7afd5a11846ea44bd65a7944fd96fea44fd543a6ec45e2cf5eed9691cc63c8f57ea44eda9ad3a12279e9afb2309923009b87e5b9da8b9ff928c9c713e515b31f07998a0e9697f6cd4a17aab4ed49762131aae8f7c7e26dbe7dfd4bbfcf1dedc4fb0101b63e4faafe2d4579f944effb9debbdaaa9b6293a7727f569cfaea5c6dd4fc7ba6968e437eff85da6abf5c88d328b5ecbedaa84fd5b99a9f972c349ef6d35aadfd03469ce659c87e17679118b9df33bb5f3f57effaef556da4ff70a5ceb51f3b3b6b3f36c4545ff637501b31acd5b9cec762ebeb3cdf1f3d1cbbfadd9db59f3371965bb99f99d8faea953a1223f7b7cdb348fb8bdf3f7964f33c6217e272709e7fef9c667379dfb7d4468cdfd4b9da2f5d44b929647d479d8b612c2e7c35bf5f8b825c70beab8ed4776aa3be5517e2abb53b10d0608a195a77e6a33ca7732cf0014738fe288f139cfec478c499e6a7f884735ce0332e3ffcac708d2f94b2fbfc2b6ef0adf2b3c577fa9e626b9f5ff0faea71ccf3ed7d7eceeb3bd8c5133cc51e9ee1395e601f0778899ff7f3c37d7ec9ebaff01abfe00d7ec56f784be38ed6dee3f7fdfcd0a92fe306ebe8a18f0daa1c90c3cafa534a46b49326c6543ba1da97800095f57b60781f3c20a5dddc4206b6b27e0f72bae33b4a15d8850718c118c674bd8afa30c17b9852e61166d8812798c302afe1b9aa3e2ce90a2baadd410f524a4fe87b0d2fd5e70300af74e62730a3dd4c60036fd88055e5fe6f30802dbcd39e0a68d1d91cd38a0db4ff5f1f3ad4233fe807e83af5d770423d52d19f700a3d67ffd5bda91f38fb57bf3dfeccf302e7fb7e9ea1c516b671f883d1a6843e2f708133e8c38056550e18409f9ec7bf7e3df81bd372939b</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>tabWidget3</tabstop>
+ <tabstop>listStations</tabstop>
+ <tabstop>buttonNewStation</tabstop>
+ <tabstop>buttonDeleteStation</tabstop>
+ <tabstop>buttonStationUp</tabstop>
+ <tabstop>buttonStationDown</tabstop>
+ <tabstop>buttonSearchStations</tabstop>
+ <tabstop>buttonLoadPresets</tabstop>
+ <tabstop>editStationName</tabstop>
+ <tabstop>editStationShortName</tabstop>
+ <tabstop>editPixmapFile</tabstop>
+ <tabstop>buttonSelectPixmapFile</tabstop>
+ <tabstop>editVolumePreset</tabstop>
+ <tabstop>editMaintainer</tabstop>
+ <tabstop>editLastChange</tabstop>
+ <tabstop>editCountry</tabstop>
+ <tabstop>editCity</tabstop>
+ <tabstop>editMedia</tabstop>
+ <tabstop>editComment</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+ <include location="global" impldecl="in implementation">qwidgetstack.h</include>
+ <include location="global" impldecl="in implementation">src/include/radiostation-listview.h</include>
+</includes>
+<pixmapfunction>SmallIconSet</pixmapfunction>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>src/include/radiostation-listview.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/radio/radio-configuration.cpp b/kradio3/plugins/radio/radio-configuration.cpp
new file mode 100644
index 0000000..321d17c
--- /dev/null
+++ b/kradio3/plugins/radio/radio-configuration.cpp
@@ -0,0 +1,592 @@
+/***************************************************************************
+ radio-configuration.cpp - description
+ -------------------
+ begin : Son Aug 3 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 "../../src/include/radiostation.h"
+#include "../../src/include/stationlist.h"
+#include "../../src/include/plugins.h"
+#include "../../src/include/radiodevice_interfaces.h"
+#include "../../src/include/standardscandialog.h"
+#include "../../src/include/radiostation-listview.h"
+#include "../../src/include/radiostation-config.h"
+#include "../../src/include/errorlog-interfaces.h"
+
+#include "radio-configuration.h"
+
+#include <math.h>
+
+#include <qlistbox.h>
+#include <klistbox.h>
+#include <qdatetimeedit.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qspinbox.h>
+#include <qpushbutton.h>
+#include <qpopupmenu.h>
+#include <qtoolbutton.h>
+#include <qwidgetstack.h>
+#include <qimage.h>
+
+#include <kfiledialog.h>
+#include <kstandarddirs.h>
+#include <kurllabel.h>
+#include <qregexp.h>
+#include <krun.h>
+#include <kurlrequester.h>
+#include <klocale.h>
+
+RadioConfiguration::RadioConfiguration (QWidget *parent, const IErrorLogClient &logger)
+ : RadioConfigurationUI(parent),
+ ignoreChanges(false),
+ devicePopup(NULL),
+ m_logger(logger),
+ m_dirty(true)
+{
+ QObject::connect(listStations, SIGNAL(sigCurrentStationChanged(int)),
+ this, SLOT(slotStationSelectionChanged(int)));
+ QObject::connect(buttonSelectPixmapFile, SIGNAL(clicked()),
+ this, SLOT(slotSelectPixmap()));
+ QObject::connect(buttonNewStation, SIGNAL(clicked()),
+ this, SLOT(slotNewStation()));
+ QObject::connect(buttonDeleteStation, SIGNAL(clicked()),
+ this, SLOT(slotDeleteStation()));
+ QObject::connect(editPixmapFile, SIGNAL(textChanged(const QString &)),
+ this, SLOT(slotPixmapChanged(const QString &)));
+ QObject::connect(editStationName, SIGNAL(textChanged(const QString &)),
+ this, SLOT(slotStationNameChanged(const QString &)));
+ QObject::connect(editStationShortName, SIGNAL(textChanged(const QString &)),
+ this, SLOT(slotStationShortNameChanged(const QString &)));
+ QObject::connect(editVolumePreset, SIGNAL(valueChanged(int)),
+ this, SLOT(slotVolumePresetChanged(int)));
+ QObject::connect(buttonStationUp, SIGNAL(clicked()),
+ this, SLOT(slotStationUp()));
+ QObject::connect(buttonStationDown, SIGNAL(clicked()),
+ this, SLOT(slotStationDown()));
+ QObject::connect(listStations, SIGNAL(sigStationActivated(int)),
+ this, SLOT(slotActivateStation( int )));
+ QObject::connect(buttonLoadPresets, SIGNAL(clicked()),
+ this, SLOT(slotLoadPresets()));
+ QObject::connect(buttonStorePresets, SIGNAL(clicked()),
+ this, SLOT(slotStorePresets()));
+ QObject::connect(buttonLastChangeNow, SIGNAL(clicked()),
+ this, SLOT(slotLastChangeNow()));
+
+ connect(editMaintainer, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty()));
+ connect(editLastChange, SIGNAL(valueChanged(const QDateTime &)), SLOT(slotSetDirty()));
+ connect(editCountry, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty()));
+ connect(editCity, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty()));
+ connect(editMedia, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty()));
+ connect(editComment, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty()));
+ connect(editPresetFile, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty()));
+
+ mailLabel->setText("mailto:witte-presets@kawo1.rwth-aachen.de");
+ mailLabel->setURL ("mailto:witte-presets@kawo1.rwth-aachen.de");
+ QObject::connect(mailLabel, SIGNAL(leftClickedURL(const QString &)),
+ this, SLOT(slotSendPresetsByMail(const QString &)));
+
+ QObject::connect(buttonSearchStations, SIGNAL(clicked()),
+ this, SLOT(slotSearchStations0()));
+
+ devicePopup = new QPopupMenu(buttonSearchStations);
+ buttonSearchStations->setPopup(devicePopup);
+ QObject::connect(devicePopup, SIGNAL(activated(int)),
+ this, SLOT(slotSearchStations(int)));
+}
+
+
+RadioConfiguration::~RadioConfiguration ()
+{
+}
+
+
+bool RadioConfiguration::connectI (Interface *i)
+{
+ bool a = IRadioClient::connectI(i);
+ bool b = IRadioDevicePoolClient::connectI(i);
+
+ return a || b;
+}
+
+bool RadioConfiguration::disconnectI (Interface *i)
+{
+ bool a = IRadioClient::disconnectI(i);
+ bool b = IRadioDevicePoolClient::disconnectI(i);
+
+ return a || b;
+}
+
+// IRadioDevicePoolClient
+
+bool RadioConfiguration::noticeDevicesChanged(const QPtrList<IRadioDevice> &l)
+{
+ QPtrListIterator<IRadioDevice> it(l);
+ devices.clear();
+ devicePopup->clear();
+ int id = 0;
+ for (; it.current(); ++it) {
+ IRadioDevice *d = it.current();
+ if (dynamic_cast<ISeekRadio*>(d)) {
+ devicePopup->insertItem(d->getDescription(), id++);
+ devices.append(d);
+ }
+ }
+ return true;
+}
+
+
+bool RadioConfiguration::noticeDeviceDescriptionChanged(const QString &)
+{
+ noticeDevicesChanged(queryDevices());
+ return true;
+}
+
+
+// IRadioClient
+
+bool RadioConfiguration::noticeStationsChanged(const StationList &sl)
+{
+ ignoreChanges = true;
+
+ m_stations = sl;
+
+ listStations->setStations(sl);
+
+ StationListMetaData &info = m_stations.metaData();
+
+ editMaintainer->setText(info.maintainer);
+ editLastChange->setDateTime(info.lastChange);
+ editCountry->setText(info.country);
+ editCity->setText(info.city);
+ editMedia->setText(info.media);
+ editComment->setText(info.comment);
+
+ ignoreChanges = false;
+
+ slotStationSelectionChanged(listStations->currentStationIndex());
+
+ return true;
+}
+
+
+bool RadioConfiguration::noticePresetFileChanged(const QString &f)
+{
+ ignoreChanges = true;
+ editPresetFile->setURL(f);
+ ignoreChanges = false;
+ return true;
+}
+
+
+void RadioConfiguration::slotStationSelectionChanged(int idx)
+{
+ RadioStation *s = NULL;
+
+ if (idx >= 0 && idx < m_stations.count()) {
+ s = &m_stations.at(idx);
+ }
+
+ editStationName ->setDisabled(!s);
+ labelStationName ->setDisabled(!s);
+ editPixmapFile ->setDisabled(!s);
+ labelPixmapFile ->setDisabled(!s);
+ editStationShortName ->setDisabled(!s);
+ labelStationShortName ->setDisabled(!s);
+ editVolumePreset ->setDisabled(!s);
+ labelVolumePreset ->setDisabled(!s);
+ buttonSelectPixmapFile->setDisabled(!s);
+ buttonDeleteStation ->setDisabled(!s);
+
+ buttonStationUp ->setDisabled(!s || idx == 0);
+ buttonStationDown ->setDisabled(!s || idx == m_stations.count()-1);
+
+ if (ignoreChanges) return;
+ ignoreChanges = true;
+
+ editStationName ->setText (s ? s->name() : QString::null);
+ editStationShortName ->setText (s ? s->shortName() : QString::null);
+ editPixmapFile ->setText (s ? s->iconName() : QString::null);
+ editVolumePreset ->setValue (s ? (int)rint(s->initialVolume()*100) : -1);
+
+ QPixmap pixmap(s ? s->iconName() : QString::null);
+ if (!pixmap.isNull()) {
+ pixmapStation->setPixmap(pixmap);
+ } else {
+ pixmapStation->setText("");
+ }
+
+
+ stackStationEdit->setDisabled(!s);
+ if (s) {
+ RadioStationConfig *c = stationEditors.find(s->getClassName());
+ if (!c) {
+ c = s->createEditor();
+ if (c) {
+ c->reparent(this, QPoint(0,0), true);
+ QObject::connect(c, SIGNAL(changed(RadioStationConfig*)),
+ this, SLOT(slotStationEditorChanged(RadioStationConfig*)));
+ stationEditors.insert(s->getClassName(), c);
+ stackStationEdit->addWidget(c);
+ }
+ }
+ if (c) {
+ c->setStationData(*s);
+ stackStationEdit->raiseWidget(c);
+ }
+ }
+
+ ignoreChanges = false;
+}
+
+
+void RadioConfiguration::slotNewStation()
+{
+ slotSetDirty();
+ const RadioStation *st = &queryCurrentStation();
+ int n = m_stations.count();
+ m_stations.all().append(st);
+ if (m_stations.count() == n) {
+ st = st->copyNewID();
+ m_stations.all().append(st);
+ }
+ if (m_stations.count() > n) {
+ listStations->appendStation(*st);
+ listStations->setCurrentStation (listStations->count()-1);
+ slotStationSelectionChanged(listStations->count()-1);
+ listStations->ensureItemVisible(listStations->selectedItem());
+ }
+}
+
+
+void RadioConfiguration::slotDeleteStation()
+{
+ int idx = listStations->currentStationIndex();
+
+ if (idx >= 0 && idx < m_stations.count()) {
+ slotSetDirty();
+ m_stations.all().remove(idx);
+ listStations->removeStation(idx);
+ }
+}
+
+
+void RadioConfiguration::slotStationEditorChanged(RadioStationConfig *c)
+{
+ if (!c) return;
+ if (ignoreChanges) return;
+
+
+ int idx = listStations->currentStationIndex();
+ if (idx >= 0 && idx < m_stations.count()) {
+ slotSetDirty();
+ RadioStation &st = m_stations.at(idx);
+
+ ignoreChanges = true;
+ bool o = listStations->signalsBlocked();
+ listStations->blockSignals(true);
+
+ c->storeStationData(st);
+ listStations->setStation(idx, st);
+
+ listStations->blockSignals(o);
+ ignoreChanges = false;
+ }
+}
+
+
+void RadioConfiguration::slotStationNameChanged( const QString & s)
+{
+ if (ignoreChanges) return;
+
+ int idx = listStations->currentStationIndex();
+ if (idx >= 0 && idx < m_stations.count()) {
+ slotSetDirty();
+ RadioStation &st = m_stations.at(idx);
+ st.setName(s);
+ ignoreChanges = true;
+ bool o = listStations->signalsBlocked();
+ listStations->blockSignals(true);
+ listStations->setStation(idx, st);
+ listStations->blockSignals(o);
+ ignoreChanges = false;
+ }
+}
+
+
+void RadioConfiguration::slotStationShortNameChanged( const QString & sn)
+{
+ if (ignoreChanges) return;
+
+ int idx = listStations->currentStationIndex();
+ if (idx >= 0 && idx < m_stations.count()) {
+ slotSetDirty();
+ RadioStation &st = m_stations.at(idx);
+ st.setShortName(sn);
+ ignoreChanges = true;
+ bool o = listStations->signalsBlocked();
+ listStations->blockSignals(true);
+ listStations->setStation(idx, st);
+ listStations->blockSignals(o);
+ ignoreChanges = false;
+ }
+}
+
+
+void RadioConfiguration::slotSelectPixmap()
+{
+ KURL url = KFileDialog::getImageOpenURL(QString::null, this,
+ i18n("Image Selection"));
+ if (!url.isEmpty()) {
+ if (url.isLocalFile()) {
+ editPixmapFile->setText(url.path());
+ } else {
+ m_logger.logWarning(i18n("ignoring non-local image"));
+ }
+ }
+}
+
+
+void RadioConfiguration::slotPixmapChanged( const QString &s )
+{
+ if (ignoreChanges) return;
+
+ int idx = listStations->currentStationIndex();
+ if (idx >= 0 && idx < m_stations.count()) {
+ slotSetDirty();
+ RadioStation &st = m_stations.at(idx);
+ st.setIconName(s);
+ ignoreChanges = true;
+ pixmapStation->setPixmap(QPixmap(s));
+ bool o = listStations->signalsBlocked();
+ listStations->blockSignals(true);
+ listStations->setStation(idx, st);
+ listStations->blockSignals(o);
+ ignoreChanges = false;
+ }
+}
+
+
+void RadioConfiguration::slotVolumePresetChanged(int v)
+{
+ int idx = listStations->currentStationIndex();
+ if (idx >= 0 && idx < m_stations.count()) {
+ slotSetDirty();
+ RadioStation &s = m_stations.at(idx);
+ s.setInitialVolume(0.01 * (double)v);
+ }
+}
+
+
+
+void RadioConfiguration::slotStationUp()
+{
+ int idx = listStations->currentStationIndex();
+ if (idx > 0 && idx < m_stations.count()) {
+ slotSetDirty();
+ RawStationList &sl = m_stations.all();
+
+ RadioStation *st = sl.take(idx-1);
+ sl.insert(idx, st);
+ delete st;
+
+ ignoreChanges = true;
+// bool o = listStations->signalsBlocked();
+// listStations->blockSignals(true);
+ listStations->setStation(idx-1, *sl.at(idx-1));
+ listStations->setStation(idx, *sl.at(idx));
+ listStations->setCurrentStation(idx-1);
+// listStations->blockSignals(o);
+ ignoreChanges = false;
+ }
+}
+
+
+void RadioConfiguration::slotStationDown()
+{
+ int idx = listStations->currentStationIndex();
+ if (idx >= 0 && idx < m_stations.count() - 1) {
+ slotSetDirty();
+ RawStationList &sl = m_stations.all();
+
+ RadioStation *st = sl.take(idx);
+ sl.insert(idx+1, st);
+ delete st;
+
+ ignoreChanges = true;
+// bool o = listStations->signalsBlocked();
+// listStations->blockSignals(true);
+ listStations->setStation(idx, *sl.at(idx));
+ listStations->setStation(idx+1, *sl.at(idx+1));
+ listStations->setCurrentStation(idx+1);
+// listStations->blockSignals(o);
+ ignoreChanges = false;
+ }
+}
+
+
+void RadioConfiguration::slotActivateStation(int idx)
+{
+ if (idx >= 0 && idx < m_stations.count()) {
+ sendActivateStation(m_stations.at(idx));
+ sendPowerOn();
+ }
+}
+
+void RadioConfiguration::slotLoadPresets()
+{
+ KFileDialog fd(locate("data", "kradio/presets/"),
+ ("*.krp|" + i18n("KRadio Preset Files")).ascii(),
+ this,
+ i18n("Preset File Selection").ascii(),
+ true);
+ fd.setMode(KFile::File | KFile::ExistingOnly);
+ fd.setCaption (i18n("Select Preset File"));
+
+ if (fd.exec() == QDialog::Accepted) {
+ slotSetDirty();
+ StationList sl;
+ if (sl.readXML(fd.selectedURL(), m_logger)) {
+ noticeStationsChanged(sl);
+ }
+ }
+}
+
+
+void RadioConfiguration::slotStorePresets()
+{
+ KFileDialog fd("",
+ ("*.krp|" + i18n("KRadio Preset Files")).ascii(),
+ this,
+ i18n("Preset File Selection").ascii(),
+ true);
+ fd.setMode(KFile::File);
+ fd.setCaption (i18n("Store Preset File"));
+
+ if (fd.exec() == QDialog::Accepted) {
+ editPresetFile->setURL(fd.selectedURL().url());
+ m_stations.writeXML(fd.selectedURL(), m_logger);
+ }
+}
+
+
+void RadioConfiguration::slotLastChangeNow()
+{
+ slotSetDirty();
+ editLastChange->setDateTime(QDateTime::currentDateTime());
+}
+
+
+static QString &urlEscapes(QString &s)
+{
+ s.replace(QRegExp("%"), "%25");
+ s.replace(QRegExp("\t"), "%09");
+ s.replace(QRegExp("\n"), "%0A");
+ s.replace(QRegExp("\n"), "%0D");
+ s.replace(QRegExp(" "), "%20");
+ s.replace(QRegExp("\\!"), "%21");
+ s.replace(QRegExp("\""), "%22");
+ s.replace(QRegExp("#"), "%23");
+ s.replace(QRegExp("\\$"), "%24");
+ s.replace(QRegExp("\\&"), "%26");
+ s.replace(QRegExp("'"), "%27");
+ s.replace(QRegExp(","), "%2C");
+ s.replace(QRegExp(":"), "%3A");
+ s.replace(QRegExp(";"), "%3B");
+ s.replace(QRegExp("="), "%3D");
+ s.replace(QRegExp("\\?"), "%3F");
+ return s;
+}
+
+void RadioConfiguration::slotSendPresetsByMail( const QString &url )
+{
+ QString presets = m_stations.writeXML(m_logger);
+
+ urlEscapes(presets);
+
+ // documentation says, krun object deletes itself,
+ // so we do not need to store the pointer
+
+ QString country = m_stations.metaData().country;
+ QString city = m_stations.metaData().city;
+ QString location = city + "/" + country;
+ urlEscapes(location);
+
+ QString cmd = url + "?subject=station preset file for " + location + "&body=";
+
+ cmd += presets;
+ new KRun (cmd);
+}
+
+
+void RadioConfiguration::slotSearchStations(int idev)
+{
+ if (idev >= 0 && (unsigned)idev < devices.count()) {
+ IRadioDevice *dev = devices.at(idev);
+
+ StandardScanDialog *x = new StandardScanDialog(NULL);
+ x->connectI(dev); // connect device
+ x->connectI(IRadioDevicePoolClient::iConnections.at(0)); // connect radio to get verbous station information
+ sendActiveDevice(dev);
+ x->show();
+ x->start();
+ if (x->exec() == QDialog::Accepted) {
+ slotSetDirty();
+ m_stations.merge(x->getStations());
+ noticeStationsChanged(m_stations);
+ }
+ delete x;
+// logDebug("scan finished");
+ }
+// logDebug("scan finished completely");
+}
+
+
+void RadioConfiguration::slotOK()
+{
+ if (m_dirty) {
+ StationListMetaData &i = m_stations.metaData();
+
+ i.maintainer = editMaintainer->text();
+ i.lastChange = editLastChange->dateTime();
+ i.country = editCountry->text();
+ i.city = editCity->text();
+ i.media = editMedia->text();
+ i.comment = editComment->text();
+
+ sendStations(m_stations);
+ sendPresetFile(editPresetFile->url());
+ m_dirty = false;
+ }
+}
+
+void RadioConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ noticeStationsChanged(queryStations());
+ noticePresetFileChanged(queryPresetFile());
+ m_dirty = false;
+ }
+}
+
+
+void RadioConfiguration::slotSetDirty()
+{
+ if (!ignoreChanges) {
+ m_dirty = true;
+ }
+}
+
+
+#include "radio-configuration.moc"
diff --git a/kradio3/plugins/radio/radio-configuration.h b/kradio3/plugins/radio/radio-configuration.h
new file mode 100644
index 0000000..31b29c8
--- /dev/null
+++ b/kradio3/plugins/radio/radio-configuration.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ radio-configuration.h - description
+ -------------------
+ begin : Son Aug 3 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIO_CONFIGURATION_H
+#define KRADIO_RADIO_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qdict.h>
+
+#include "../../src/include/radio_interfaces.h"
+#include "../../src/include/stationlist.h"
+#include "../../src/include/radiodevicepool_interfaces.h"
+#include "radio-configuration-ui.h"
+
+class QPopupMenu;
+class RadioStationConfig;
+
+class RadioConfiguration : public RadioConfigurationUI,
+ public IRadioClient,
+ public IRadioDevicePoolClient
+{
+Q_OBJECT
+public :
+ RadioConfiguration (QWidget *parent, const IErrorLogClient &m_logger);
+ ~RadioConfiguration ();
+
+ bool connectI (Interface *i);
+ bool disconnectI (Interface *i);
+
+ // IRadioDevicePoolClient
+
+RECEIVERS:
+ bool noticeActiveDeviceChanged(IRadioDevice *) { return false; }
+ bool noticeDevicesChanged(const QPtrList<IRadioDevice> &);
+ bool noticeDeviceDescriptionChanged(const QString &);
+
+ // IRadioClient
+
+RECEIVERS:
+ bool noticePowerChanged(bool /*on*/) { return false; } // don't care
+ bool noticeStationChanged (const RadioStation &, int /*idx*/) { return false; } // don't care
+ bool noticeStationsChanged(const StationList &sl);
+ bool noticePresetFileChanged(const QString &f);
+
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; }
+
+protected slots:
+
+ void slotStationSelectionChanged(int idx);
+ void slotNewStation();
+ void slotDeleteStation();
+ void slotStationEditorChanged(RadioStationConfig *c);
+ void slotStationNameChanged( const QString & s);
+ void slotStationShortNameChanged( const QString & sn);
+ void slotPixmapChanged( const QString &s );
+ void slotSelectPixmap();
+ void slotVolumePresetChanged(int v);
+ void slotStationUp();
+ void slotStationDown();
+ void slotActivateStation( int );
+ void slotLoadPresets();
+ void slotStorePresets();
+ void slotLastChangeNow();
+ void slotSendPresetsByMail( const QString &url );
+
+ void slotSearchStations(int i);
+ void slotSearchStations0() { slotSearchStations(0); }
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+
+protected:
+
+ StationList m_stations;
+ bool ignoreChanges;
+
+ QPopupMenu *devicePopup;
+ QPtrList<IRadioDevice> devices;
+
+ QDict<RadioStationConfig> stationEditors;
+
+ const IErrorLogClient &m_logger;
+ bool m_dirty;
+};
+
+#endif
+
diff --git a/kradio3/plugins/radio/radio.cpp b/kradio3/plugins/radio/radio.cpp
new file mode 100644
index 0000000..2320f56
--- /dev/null
+++ b/kradio3/plugins/radio/radio.cpp
@@ -0,0 +1,497 @@
+/***************************************************************************
+ 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 QString &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(QString("radio-") + name());
+
+ config->writeEntry("presetfile", m_presetFile);
+
+ m_stationList.writeXML(m_presetFile, *this);
+}
+
+
+void Radio::restoreState (KConfig *config)
+{
+ config->setGroup(QString("radio-") + name());
+
+ m_presetFile = config->readEntry("presetfile",
+ QString::null);
+ 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 QString &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 QPtrList<IRadioDevice> &Radio::getDevices() const
+{
+ return IRadioDeviceClient::iConnections;
+}
+
+
+const QString &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 QString qstrUnknown(I18N_NOOP("unknown"));
+static QString i18nqstrUnknown;
+const QString &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 QString &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();
+}
+
diff --git a/kradio3/plugins/radio/radio.h b/kradio3/plugins/radio/radio.h
new file mode 100644
index 0000000..7913c16
--- /dev/null
+++ b/kradio3/plugins/radio/radio.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+ radio.h - 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RADIO_H
+#define KRADIO_RADIO_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "../../src/include/radio_interfaces.h"
+#include "../../src/include/radiodevicepool_interfaces.h"
+#include "../../src/include/radiodevice_interfaces.h"
+#include "../../src/include/timecontrol_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "../../src/include/stationlist.h"
+#include "../../src/include/plugins.h"
+
+/**
+ * The main Radio class, which is used as the interface of the radio functionality
+ * to the GUI parts of the application
+ * @author Klas Kalass, Ernst Martin Witte
+ */
+
+/////////////////////////////////////////////////////////////////////////////
+
+/* A class, that is able to manage more than one radio device, one of those
+ is active at a time. This class behaves represents the active device,
+ the active devices can be changed either by selecting a station or by
+ explicitly changing the devices.
+
+ At any time a valid active device exists as long as any device is connected.
+
+*/
+
+class Radio : public PluginBase,
+ public IRadio,
+ public IRadioDevicePool,
+ public IRadioDeviceClient,
+ public ITimeControlClient,
+ public ISoundStreamClient
+{
+public:
+ Radio(const QString &name);
+ ~Radio();
+
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual QString pluginClassName() const { return "Radio"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ virtual void aboutToQuit();
+
+ // IRadio methods
+
+RECEIVERS:
+ bool powerOn() { return sendPowerOn() > 0; }
+ bool powerOff() { return sendPowerOff() > 0; }
+ bool activateStation(const RadioStation &rs);
+ bool activateStation(int index);
+ bool setStations(const StationList &sl);
+ bool setPresetFile(const QString &presetFile);
+
+ANSWERS:
+ bool isPowerOn() const { return queryIsPowerOn(); }
+ bool isPowerOff() const { return queryIsPowerOff(); }
+ const RadioStation & getCurrentStation() const { return queryCurrentStation(); }
+ int getStationIdx(const RadioStation &) const;
+ int getCurrentStationIdx() const;
+ const StationList & getStations() const { return m_stationList; }
+ const QString & getPresetFile() const { return m_presetFile; }
+
+ SoundStreamID getCurrentSoundStreamID() const;
+
+
+public:
+ bool connectI (Interface *i);
+ bool disconnectI (Interface *i);
+
+ void noticeConnectedI (IRadioDeviceClient::cmplInterface *i, bool pointer_valid);
+ void noticeDisconnectI(IRadioDeviceClient::cmplInterface *i, bool pointer_valid);
+
+ // IRadioDevicePool methods
+
+RECEIVERS:
+ bool setActiveDevice(IRadioDevice *rd, bool keepPower = true);
+
+ANSWERS:
+ IRadioDevice * getActiveDevice() const;
+ const QPtrList<IRadioDevice> & getDevices() const;
+ const QString & getDeviceDescription() const;
+
+
+
+ // IRadioDeviceClient methods, even sending methods overwritten
+ // to provide "1-of-N" functionality
+
+SENDERS:
+ IF_SENDER ( sendPowerOn() )
+ IF_SENDER ( sendPowerOff() )
+ IF_SENDER ( sendActivateStation (const RadioStation &rs) )
+
+QUERIES:
+ IF_QUERY ( bool queryIsPowerOn() )
+ IF_QUERY ( bool queryIsPowerOff() )
+ IF_QUERY ( const RadioStation & queryCurrentStation() )
+ IF_QUERY ( const QString & queryDescription() )
+ IF_QUERY ( SoundStreamID queryCurrentSoundStreamID() )
+
+RECEIVERS:
+ virtual bool noticePowerChanged (bool on, const IRadioDevice *sender = NULL);
+ virtual bool noticeStationChanged (const RadioStation &rs, const IRadioDevice *sender = NULL);
+ virtual bool noticeDescriptionChanged (const QString &, const IRadioDevice *sender = NULL);
+
+ virtual bool noticeCurrentSoundStreamIDChanged(SoundStreamID id, const IRadioDevice *sender = NULL);
+
+ // ITimeControlClient
+
+RECEIVERS:
+ bool noticeAlarmsChanged(const AlarmVector &) { return false; } // ignore
+ bool noticeAlarm(const Alarm &);
+ bool noticeNextAlarmChanged(const Alarm *) { return false; } // ignore
+ bool noticeCountdownStarted(const QDateTime &/*end*/){ return false; } // ignore
+ bool noticeCountdownStopped() { return false; } // ignore
+ bool noticeCountdownZero();
+ bool noticeCountdownSecondsChanged(int /*n*/) { return false; } // ignore
+
+ // ISoundStreamClient
+
+RECEIVERS:
+
+ // ...
+
+protected:
+
+ QString m_presetFile;
+ StationList m_stationList;
+ IRadioDevice *m_activeDevice;
+};
+
+
+#endif
diff --git a/kradio3/plugins/recording/Makefile.am b/kradio3/plugins/recording/Makefile.am
new file mode 100644
index 0000000..1cbd6aa
--- /dev/null
+++ b/kradio3/plugins/recording/Makefile.am
@@ -0,0 +1,22 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = librecording.la
+librecording_la_SOURCES = recording-configuration.cpp \
+ recording-configuration-ui.ui recording.cpp recording-config.cpp reccfg_interfaces.cpp encoder.cpp \
+ recording-datamonitor.cpp recording-monitor.cpp encoder_mp3.cpp encoder_ogg.cpp encoder_pcm.cpp
+librecording_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+librecording_la_LIBADD = $(LIB_OGG) $(LIB_LAME)
+
+noinst_HEADERS = recording-configuration.h recording.h recording-config.h \
+ reccfg_interfaces.h encoder.h soundstreamevent.h recording-datamonitor.h \
+ recording-monitor.h encoder_mp3.h encoder_ogg.h encoder_pcm.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-recording.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-recording.pot
diff --git a/kradio3/plugins/recording/encoder.cpp b/kradio3/plugins/recording/encoder.cpp
new file mode 100644
index 0000000..b33a8c3
--- /dev/null
+++ b/kradio3/plugins/recording/encoder.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+ encoder.cpp - description
+ -------------------
+ begin : Thu May 05 2005
+ copyright : (C) 2005 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 "../../src/include/radiostation.h"
+#include "../../src/include/errorlog-interfaces.h"
+#include "../../src/include/aboutwidget.h"
+
+#include "recording.h"
+#include "recording-configuration.h"
+#include "soundstreamevent.h"
+
+#include <qsocketnotifier.h>
+#include <qevent.h>
+#include <qapplication.h>
+#include <qregexp.h>
+
+#include <kconfig.h>
+#include <kdeversion.h>
+#include <klocale.h>
+
+RecordingEncoding::RecordingEncoding(QObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const QString &filename)
+ :
+ m_parent(parent),
+ m_config(cfg),
+ m_RadioStation(rs ? rs->copy() : NULL),
+ m_SoundStreamID(ssid),
+ m_error(false),
+ m_errorString(QString::null),
+ m_done(false),
+ m_InputBuffers(m_config.m_EncodeBufferCount < 3 ? 3 : m_config.m_EncodeBufferCount,
+ m_config.m_EncodeBufferSize < 4096 ? 4096 : m_config.m_EncodeBufferSize),
+ m_buffersMetaData(NULL),
+ m_encodedSize(0),
+ m_InputStartTime(0),
+ m_InputStartPosition(0),
+ m_outputURL(filename)
+{
+
+ if (m_config.m_EncodeBufferCount < 3)
+ m_config.m_EncodeBufferCount = 3;
+ if (m_config.m_EncodeBufferSize < 4096)
+ m_config.m_EncodeBufferSize = 4096;
+
+ m_buffersMetaData = new QPtrList<BufferSoundMetaData> *[m_config.m_EncodeBufferCount];
+ for (size_t i = 0; i < m_config.m_EncodeBufferCount; ++i) {
+ m_buffersMetaData [i] = new QPtrList<BufferSoundMetaData>;
+ m_buffersMetaData [i]->setAutoDelete(true);
+ }
+}
+
+
+RecordingEncoding::~RecordingEncoding()
+{
+ for (size_t i = 0; i < m_config.m_EncodeBufferCount; ++i) {
+ delete m_buffersMetaData[i];
+ }
+ delete m_buffersMetaData;
+ delete m_RadioStation;
+}
+
+
+char *RecordingEncoding::lockInputBuffer(size_t &bufferSize)
+{
+ if (m_done || m_error)
+ return NULL;
+ char * retval = m_InputBuffers.lockWriteBuffer(bufferSize);
+
+ m_error |= m_InputBuffers.hasError();
+ m_errorString += m_InputBuffers.getErrorString();
+ m_InputBuffers.resetError();
+
+ return retval;
+}
+
+
+void RecordingEncoding::unlockInputBuffer(size_t bufferSize, const SoundMetaData &md)
+{
+ if (m_done)
+ return;
+ size_t bufidx = m_InputBuffers.getCurrentWriteBufferIdx();
+ size_t buffill = m_InputBuffers.getWriteBufferFill();
+ m_InputBuffers.unlockWriteBuffer(bufferSize);
+
+ if (!m_InputBuffers.hasError()) {
+ if (!m_InputStartTime) {
+ m_InputStartTime = md.absoluteTimestamp();
+ m_InputStartPosition = md.position();
+ }
+ BufferSoundMetaData *bmd = new BufferSoundMetaData(
+ md.position() - m_InputStartPosition,
+ md.absoluteTimestamp() - m_InputStartTime,
+ md.absoluteTimestamp(),
+ md.url(),
+ buffill);
+ m_buffersMetaData[bufidx]->append(bmd);
+ } else {
+ m_error = true;
+ m_errorString += m_InputBuffers.getErrorString();
+ m_InputBuffers.resetError();
+ }
+}
+
+
+void RecordingEncoding::setDone()
+{
+ m_done = true;
+ m_InputBuffers.unlockAllWriteBuffers();
+}
+
+
+
+void RecordingEncoding::run()
+{
+ BufferSoundMetaData last_md;
+
+ while (!m_error) {
+ char *buffer = NULL;
+ size_t buffer_fill = 0;
+ if (!m_done) {
+ buffer = m_InputBuffers.wait4ReadBuffer(buffer_fill);
+ }
+
+ if (!buffer_fill) {
+ if (m_done)
+ break;
+ else
+ continue;
+ }
+
+ char *export_buffer = NULL;
+ size_t export_buffer_size = 0;
+
+ Q_UINT64 old_pos = m_encodedSize;
+
+ encode(buffer, buffer_fill, export_buffer, export_buffer_size);
+
+ SoundStreamEncodingStepEvent *step_event = NULL;
+
+ if (!m_error) {
+ last_md = *m_buffersMetaData[m_InputBuffers.getCurrentReadBufferIdx()]->first();
+ SoundMetaData md(old_pos, last_md.relativeTimestamp(), last_md.absoluteTimestamp(), m_outputURL);
+ step_event = new SoundStreamEncodingStepEvent(m_SoundStreamID, export_buffer, export_buffer_size, md);
+ }
+
+ if (step_event)
+ QApplication::postEvent(m_parent, step_event);
+ }
+ m_done = true;
+ closeOutput();
+
+ SoundMetaData md(m_encodedSize, last_md.relativeTimestamp(), last_md.absoluteTimestamp(), m_outputURL);
+ QApplication::postEvent(m_parent, new SoundStreamEncodingStepEvent(m_SoundStreamID, NULL, 0, md));
+
+ QApplication::postEvent(m_parent, new SoundStreamEncodingTerminatedEvent(m_SoundStreamID));
+}
+
diff --git a/kradio3/plugins/recording/encoder.h b/kradio3/plugins/recording/encoder.h
new file mode 100644
index 0000000..271cf83
--- /dev/null
+++ b/kradio3/plugins/recording/encoder.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ encoder.h - description
+ -------------------
+ begin : Thu May 05 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_H
+#define KRADIO_RECORDING_ENCODER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qthread.h>
+
+#include "../../src/include/radiostation.h"
+#include "../../src/include/multibuffer.h"
+#include "../../src/include/sound_metadata.h"
+#include "../../src/include/soundstreamid.h"
+#include "recording-config.h"
+
+class BufferSoundMetaData : public SoundMetaData
+{
+public:
+ BufferSoundMetaData()
+ : SoundMetaData(0, 0, 0, KURL()), m_BufferPosition(0) {}
+ BufferSoundMetaData(const SoundMetaData &md, size_t bufferpos)
+ : SoundMetaData(md), m_BufferPosition(bufferpos) {}
+ BufferSoundMetaData(Q_INT64 pos, time_t rel, time_t abs, const KURL &url, size_t bufferpos)
+ : SoundMetaData(pos, rel, abs, url), m_BufferPosition(bufferpos) {}
+
+ size_t bufferPosition() const { return m_BufferPosition; }
+
+protected:
+ size_t m_BufferPosition;
+};
+
+
+class RecordingEncoding : public QThread
+{
+public:
+ RecordingEncoding(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename);
+ virtual ~RecordingEncoding();
+
+ void run();
+
+ char *lockInputBuffer(size_t &bufferSize); // bytes we whish to write, returns number of bytes available
+ void unlockInputBuffer(size_t bufferSize, const SoundMetaData &md); // bytes we actually wrote
+
+ bool error() const { return m_error; }
+ const QString &errorString() const { return m_errorString; }
+
+ void setDone();
+ bool IsDone() { return m_done; }
+
+ virtual bool openOutput(const QString &outputFile) = 0;
+ virtual void closeOutput() = 0;
+
+ Q_UINT64 encodedSize() const { return m_encodedSize; }
+
+ const RecordingConfig &config() const { return m_config; }
+
+protected:
+ virtual void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size) = 0;
+
+ QObject *m_parent;
+ RecordingConfig m_config;
+ RadioStation *m_RadioStation;
+ SoundStreamID m_SoundStreamID;
+
+ bool m_error;
+ QString m_errorString;
+ bool m_done;
+
+ MultiBuffer m_InputBuffers;
+ QPtrList<BufferSoundMetaData>
+ **m_buffersMetaData;
+ Q_UINT64 m_encodedSize;
+
+ time_t m_InputStartTime;
+ Q_UINT64 m_InputStartPosition;
+
+ KURL m_outputURL;
+};
+
+
+#endif
diff --git a/kradio3/plugins/recording/encoder_mp3.cpp b/kradio3/plugins/recording/encoder_mp3.cpp
new file mode 100644
index 0000000..5ba0bc2
--- /dev/null
+++ b/kradio3/plugins/recording/encoder_mp3.cpp
@@ -0,0 +1,214 @@
+/***************************************************************************
+ encoder_mp3.cpp
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 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 "encoder_mp3.h"
+
+#include <qmutex.h>
+#include <klocale.h>
+
+RecordingEncodingMP3::RecordingEncodingMP3(QObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const QString &filename)
+ : RecordingEncoding(parent, ssid, cfg, rs, filename)
+#ifdef HAVE_LAME
+ ,
+ m_MP3Buffer(NULL),
+ m_MP3BufferSize(0),
+ m_MP3Output(NULL),
+ m_ID3Tags(NULL),
+ m_LAMEFlags(NULL),
+ m_MP3LBuffer(NULL),
+ m_MP3RBuffer(NULL)
+#endif
+{
+ m_config.m_OutputFormat = RecordingConfig::outputMP3;
+ m_config.m_SoundFormat.m_Encoding = "mp3";
+ openOutput(filename);
+}
+
+
+RecordingEncodingMP3::~RecordingEncodingMP3()
+{
+ closeOutput();
+}
+
+
+static QMutex lameSerialization;
+
+void RecordingEncodingMP3::encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size)
+{
+ if (m_error)
+ return;
+
+#ifdef HAVE_LAME
+ short int *buffer = (short int*)_buffer;
+ size_t j = 0,
+ j_inc = (m_config.m_SoundFormat.m_Channels == 1) ? 1 : 2,
+ dj = (m_config.m_SoundFormat.m_Channels == 1) ? 0 : 1,
+ samples = buffer_size / m_config.m_SoundFormat.frameSize();
+
+ for (size_t i = 0; i < samples; ++i, j+=j_inc) {
+ m_MP3LBuffer[i] = buffer[j];
+ m_MP3RBuffer[i] = buffer[j+dj];
+ }
+
+ int n = 0;
+ lameSerialization.lock();
+ n = lame_encode_buffer(m_LAMEFlags,
+ m_MP3LBuffer,
+ m_MP3RBuffer,
+ samples,
+ m_MP3Buffer,
+ m_MP3BufferSize);
+ lameSerialization.unlock();
+ if (n < 0) {
+ m_errorString += i18n("Error %1 while encoding mp3. ").arg(QString().setNum(n));
+ m_error = true;
+ } else if (n > 0) {
+ m_encodedSize += n;
+
+ export_buffer = (char*)m_MP3Buffer;
+ export_buffer_size = n;
+ int r = fwrite(m_MP3Buffer, 1, n, m_MP3Output);
+
+ if (r <= 0) {
+ m_errorString += i18n("Error %1 writing output. ").arg(QString().setNum(r));
+ m_error = true;
+ }
+ }
+#endif
+}
+
+
+
+bool RecordingEncodingMP3::openOutput(const QString &output)
+{
+#ifdef HAVE_LAME
+// m_output = NULL;
+ m_LAMEFlags = lame_init();
+
+ if (!m_LAMEFlags) {
+ m_error = true;
+ m_errorString += i18n("Cannot initialize lalibmp3lame. ");
+ } else {
+ lame_set_in_samplerate(m_LAMEFlags, m_config.m_SoundFormat.m_SampleRate);
+ lame_set_num_channels(m_LAMEFlags, 2);
+ //lame_set_quality(m_LAMEFlags, m_config.mp3Quality);
+
+ lame_set_mode(m_LAMEFlags, m_config.m_SoundFormat.m_Channels == 1 ? MONO : JOINT_STEREO);
+
+ // lame_seterrorf(m_LAMEFlags, ...);
+ // lame_setdebugf(m_LAMEFlags, ...);
+ // lame_setmsgf(m_LAMEFlags, ...);
+
+ lame_set_VBR(m_LAMEFlags, vbr_default);
+ lame_set_VBR_q(m_LAMEFlags, m_config.m_mp3Quality);
+
+ if (lame_init_params(m_LAMEFlags) < 0) {
+ m_error = true;
+ m_errorString += i18n("Cannot initialize libmp3lame parameters. ").arg(output);
+ }
+
+ if (!m_error) {
+ id3tag_init(m_LAMEFlags);
+ id3tag_add_v2(m_LAMEFlags);
+ QString title = m_RadioStation->name() + QString().sprintf(" - %s", (QDateTime::currentDateTime().toString(Qt::ISODate)).ascii());
+ QString comment = i18n("Recorded by KRadio");
+ size_t l = title.length() + comment.length() + 10;
+ m_ID3Tags = new char[l];
+ char *ctitle = m_ID3Tags;
+ strcpy(ctitle, title.latin1());
+ char *ccomment = m_ID3Tags + strlen(ctitle) + 1;
+ strcpy(ccomment, comment.latin1());
+ id3tag_set_title(m_LAMEFlags, ctitle);
+ id3tag_set_comment(m_LAMEFlags, ccomment);
+ }
+
+ m_MP3Output = fopen(output.ascii(), "wb+");
+ if (!m_MP3Output) {
+ m_errorString += i18n("Cannot open output file %1. ").arg(output);
+ m_error = true;
+ }
+
+ size_t nSamples = m_config.m_EncodeBufferSize / m_config.m_SoundFormat.frameSize();
+ m_MP3BufferSize = nSamples + nSamples / 4 + 7200;
+ m_MP3Buffer = new unsigned char[m_MP3BufferSize];
+
+ m_MP3LBuffer = new short int[nSamples];
+ m_MP3RBuffer = new short int[nSamples];
+
+ if (!m_MP3Buffer || !m_MP3LBuffer || !m_MP3RBuffer) {
+ m_error = true;
+ m_errorString += i18n("Cannot allocate buffers for mp3 encoding. ");
+ }
+ }
+
+ if (m_error) {
+ if (m_LAMEFlags) lame_close(m_LAMEFlags);
+ m_LAMEFlags = NULL;
+ if (m_MP3Output) fclose(m_MP3Output);
+ m_MP3Output = NULL;
+ if (m_MP3Buffer) delete [] m_MP3Buffer;
+ m_MP3Buffer = NULL;
+ m_MP3BufferSize = 0;
+ if (m_ID3Tags) delete [] m_ID3Tags;
+ m_ID3Tags = NULL;
+ if (m_MP3LBuffer) delete[] m_MP3LBuffer;
+ if (m_MP3RBuffer) delete[] m_MP3RBuffer;
+ m_MP3LBuffer = m_MP3RBuffer = NULL;
+ }
+#endif
+ return !m_error;
+}
+
+
+void RecordingEncodingMP3::closeOutput()
+{
+#ifdef HAVE_LAME
+ if (m_LAMEFlags) {
+ if (m_config.m_OutputFormat == RecordingConfig::outputMP3) {
+ int n = lame_encode_flush(m_LAMEFlags,
+ m_MP3Buffer,
+ m_MP3BufferSize);
+ if (n < 0) {
+ m_error = true;
+ m_errorString += i18n("Error %1 while encoding mp3. ").arg(QString().setNum(n));
+ } else if (n > 0) {
+ int r = fwrite(m_MP3Buffer, 1, n, m_MP3Output);
+ if (r <= 0) {
+ m_error = true;
+ m_errorString += i18n("Error %1 writing output. ").arg(QString().setNum(r));
+ } else {
+ lame_mp3_tags_fid(m_LAMEFlags, m_MP3Output);
+ }
+ }
+ }
+ if (m_LAMEFlags) lame_close(m_LAMEFlags);
+ m_LAMEFlags = NULL;
+ if (m_MP3Output) fclose(m_MP3Output);
+ m_MP3Output = NULL;
+ m_MP3BufferSize = 0;
+ if (m_MP3Buffer) delete [] m_MP3Buffer;
+ m_MP3Buffer = NULL;
+ if (m_ID3Tags) delete [] m_ID3Tags;
+ m_ID3Tags = NULL;
+ if (m_MP3LBuffer) delete[] m_MP3LBuffer;
+ if (m_MP3RBuffer) delete[] m_MP3RBuffer;
+ m_MP3LBuffer = m_MP3RBuffer = NULL;
+ }
+#endif
+}
diff --git a/kradio3/plugins/recording/encoder_mp3.h b/kradio3/plugins/recording/encoder_mp3.h
new file mode 100644
index 0000000..2a41832
--- /dev/null
+++ b/kradio3/plugins/recording/encoder_mp3.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ encoder_mp3.h
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_MP3_H
+#define KRADIO_RECORDING_ENCODER_MP3_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "encoder.h"
+
+#ifdef HAVE_LAME
+ #include <lame/lame.h>
+#endif
+
+class RecordingEncodingMP3 : public RecordingEncoding
+{
+public:
+ RecordingEncodingMP3(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename);
+ virtual ~RecordingEncodingMP3();
+
+ bool openOutput(const QString &outputFile);
+ void closeOutput();
+
+protected:
+ void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size);
+
+#ifdef HAVE_LAME
+ unsigned char *m_MP3Buffer;
+ size_t m_MP3BufferSize;
+ FILE *m_MP3Output;
+ char *m_ID3Tags;
+ lame_global_flags *m_LAMEFlags;
+ short int *m_MP3LBuffer,
+ *m_MP3RBuffer;
+#endif
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/recording/encoder_ogg.cpp b/kradio3/plugins/recording/encoder_ogg.cpp
new file mode 100644
index 0000000..e3db6cc
--- /dev/null
+++ b/kradio3/plugins/recording/encoder_ogg.cpp
@@ -0,0 +1,250 @@
+/***************************************************************************
+ encoder_ogg.cpp
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 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 "encoder_ogg.h"
+
+#include <klocale.h>
+#include <stdlib.h>
+
+RecordingEncodingOgg::RecordingEncodingOgg(QObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const QString &filename)
+ : RecordingEncoding(parent, ssid, cfg, rs, filename)
+#ifdef HAVE_OGG
+ ,
+ m_OggOutput(NULL),
+ m_OggExportBuffer(NULL),
+ m_OggExportBufferSize(0)
+#endif
+{
+ m_config.m_OutputFormat = RecordingConfig::outputOGG;
+ m_config.m_SoundFormat.m_Encoding = "ogg";
+ openOutput(filename);
+}
+
+
+RecordingEncodingOgg::~RecordingEncodingOgg()
+{
+ closeOutput();
+}
+
+void RecordingEncodingOgg::encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size)
+{
+ if (m_error)
+ return;
+
+#ifdef HAVE_OGG
+ SoundFormat &sf = m_config.m_SoundFormat;
+ ogg_page ogg_pg;
+ ogg_packet ogg_pkt;
+
+ size_t samples = buffer_size / sf.frameSize();
+
+ // buffer[channel][sample], normalized to -1..0..+1
+ float **buffer = vorbis_analysis_buffer(&m_VorbisDSP, (samples < 512 ? 512 : samples));
+
+ sf.convertSamplesToFloat(_buffer, buffer, samples);
+
+ /* Tell the library how many samples (per channel) we wrote
+ into the supplied buffer */
+ vorbis_analysis_wrote(&m_VorbisDSP, samples);
+
+ /* While we can get enough data from the library to analyse, one
+ block at a time... */
+
+ bool eos = false;
+ while(!m_error && !eos && vorbis_analysis_blockout(&m_VorbisDSP, &m_VorbisBlock) == 1) {
+
+ /* Do the main analysis, creating a packet */
+ vorbis_analysis(&m_VorbisBlock, NULL);
+ vorbis_bitrate_addblock(&m_VorbisBlock);
+
+ while(!m_error && vorbis_bitrate_flushpacket(&m_VorbisDSP, &ogg_pkt)) {
+ /* Add packet to bitstream */
+ ogg_stream_packetin(&m_OggStream,&ogg_pkt);
+
+ /* If we've gone over a page boundary, we can do actual output,
+ so do so (for however many pages are available) */
+
+ while(!m_error && !eos) {
+ int result = ogg_stream_pageout(&m_OggStream, &ogg_pg);
+ if (!result) break;
+
+ int n = fwrite(ogg_pg.header, 1, ogg_pg.header_len, m_OggOutput);
+ n += fwrite(ogg_pg.body, 1, ogg_pg.body_len, m_OggOutput);
+
+ m_encodedSize += n;
+
+ if (n != (ogg_pg.header_len + ogg_pg.body_len)) {
+ m_error = true;
+ m_errorString += i18n("Failed writing data to ogg/vorbis output stream. ");
+ break;
+ } else {
+
+ if (m_OggExportBufferSize < export_buffer_size + n) {
+ m_OggExportBuffer = (char*)realloc(m_OggExportBuffer, m_OggExportBufferSize + 2 * n);
+ m_OggExportBufferSize += 2 * n;
+ }
+
+ memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.header, ogg_pg.header_len);
+ export_buffer_size += ogg_pg.header_len;
+ memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.body, ogg_pg.body_len);
+ export_buffer_size += ogg_pg.body_len;
+
+ }
+ if (ogg_page_eos(&ogg_pg))
+ eos = 1;
+ }
+ }
+ }
+
+ export_buffer = m_OggExportBuffer;
+#endif
+}
+
+
+#ifdef HAVE_OGG
+static void vorbis_comment_add_tag_new(vorbis_comment *vc, const QString &tag, const QString &value)
+{
+ char *stag = strdup(tag.ascii());
+ char *svalue = strdup(value.utf8());
+ vorbis_comment_add_tag(vc, stag, svalue);
+ delete stag;
+ delete svalue;
+}
+#endif
+
+bool RecordingEncodingOgg::openOutput(const QString &output)
+{
+#ifdef HAVE_OGG
+ m_OggOutput = fopen(output.ascii(), "wb+");
+ if (!m_OggOutput) {
+ m_errorString += i18n("Cannot open Ogg/Vorbis output file %1. ").arg(output);
+ m_error = true;
+ }
+
+ m_OggExportBuffer = (char*)malloc(m_OggExportBufferSize = 65536); // start with a 64k buffer
+
+
+ /* Have vorbisenc choose a mode for us */
+ vorbis_info_init(&m_VorbisInfo);
+
+ SoundFormat &sf = m_config.m_SoundFormat;
+ if (vorbis_encode_setup_vbr(&m_VorbisInfo, sf.m_Channels, sf.m_SampleRate, m_config.m_oggQuality)) {
+ m_error = true;
+ m_errorString = i18n("Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n");
+ vorbis_info_clear(&m_VorbisInfo);
+ return false;
+ }
+
+ /* Turn off management entirely (if it was turned on). */
+ vorbis_encode_ctl(&m_VorbisInfo, OV_ECTL_RATEMANAGE_SET, NULL);
+ vorbis_encode_setup_init(&m_VorbisInfo);
+
+ /* Now, set up the analysis engine, stream encoder, and other
+ preparation before the encoding begins.
+ */
+
+ vorbis_analysis_init(&m_VorbisDSP, &m_VorbisInfo);
+ vorbis_block_init(&m_VorbisDSP, &m_VorbisBlock);
+
+ ogg_stream_init (&m_OggStream, m_SoundStreamID.getID());
+
+ /* Now, build the three header packets and send through to the stream
+ output stage (but defer actual file output until the main encode loop) */
+
+ ogg_packet header_main;
+ ogg_packet header_comments;
+ ogg_packet header_codebooks;
+
+ /* Build the packets */
+ vorbis_comment vc;
+ vorbis_comment_init (&vc);
+ vorbis_comment_add_tag_new(&vc, "creator", "KRadio" VERSION);
+ vorbis_comment_add_tag_new(&vc, "title", m_RadioStation->longName().utf8());
+ vorbis_comment_add_tag_new(&vc, "date", QDateTime::currentDateTime().toString(Qt::ISODate));
+
+ vorbis_analysis_headerout(&m_VorbisDSP, &vc,
+ &header_main, &header_comments, &header_codebooks);
+
+ /* And stream them out */
+ ogg_stream_packetin(&m_OggStream, &header_main);
+ ogg_stream_packetin(&m_OggStream, &header_comments);
+ ogg_stream_packetin(&m_OggStream, &header_codebooks);
+
+ int result;
+ ogg_page ogg_page;
+ while((result = ogg_stream_flush(&m_OggStream, &ogg_page))) {
+
+ if (!result) break;
+
+ int n = fwrite(ogg_page.header, 1, ogg_page.header_len, m_OggOutput);
+ n += fwrite(ogg_page.body, 1, ogg_page.body_len, m_OggOutput);
+
+ if(n != ogg_page.header_len + ogg_page.body_len) {
+ m_error = true;
+ m_errorString += i18n("Failed writing Ogg/Vorbis header to output stream\n");
+ break;
+ }
+ }
+
+ vorbis_comment_clear (&vc);
+
+ if (m_error) {
+ if (m_OggOutput) fclose (m_OggOutput);
+ m_OggOutput = NULL;
+ free(m_OggExportBuffer);
+ m_OggExportBuffer = NULL;
+ m_OggExportBufferSize = 0;
+
+ ogg_stream_clear(&m_OggStream);
+ vorbis_block_clear(&m_VorbisBlock);
+ vorbis_dsp_clear(&m_VorbisDSP);
+ vorbis_info_clear(&m_VorbisInfo);
+ }
+
+ return !m_error;
+#endif
+}
+
+
+void RecordingEncodingOgg::closeOutput()
+{
+#ifdef HAVE_OGG
+ if (m_OggOutput) {
+
+ char *tmp_buf = NULL;
+ size_t tmp_size = 0;
+ // flush buffer
+ encode(tmp_buf, tmp_size, tmp_buf, tmp_size);
+
+ fclose(m_OggOutput);
+ m_OggOutput = NULL;
+
+ free(m_OggExportBuffer);
+ m_OggExportBuffer = NULL;
+ m_OggExportBufferSize = 0;
+
+ ogg_stream_clear(&m_OggStream);
+ vorbis_block_clear(&m_VorbisBlock);
+ vorbis_dsp_clear(&m_VorbisDSP);
+ vorbis_info_clear(&m_VorbisInfo);
+ }
+#endif
+}
+
+
diff --git a/kradio3/plugins/recording/encoder_ogg.h b/kradio3/plugins/recording/encoder_ogg.h
new file mode 100644
index 0000000..55cf8e6
--- /dev/null
+++ b/kradio3/plugins/recording/encoder_ogg.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ encoder_ogg.h
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_OGG_H
+#define KRADIO_RECORDING_ENCODER_OGG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "encoder.h"
+
+#ifdef HAVE_OGG
+ #include <vorbis/vorbisenc.h>
+#endif
+
+class RecordingEncodingOgg : public RecordingEncoding
+{
+public:
+ RecordingEncodingOgg(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename);
+ virtual ~RecordingEncodingOgg();
+
+ bool openOutput(const QString &outputFile);
+ void closeOutput();
+
+protected:
+ void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size);
+
+#ifdef HAVE_OGG
+ FILE *m_OggOutput;
+ char *m_OggExportBuffer;
+ size_t m_OggExportBufferSize;
+ ogg_stream_state m_OggStream;
+ vorbis_dsp_state m_VorbisDSP;
+ vorbis_block m_VorbisBlock;
+ vorbis_info m_VorbisInfo;
+#endif
+};
+
+
+#endif
diff --git a/kradio3/plugins/recording/encoder_pcm.cpp b/kradio3/plugins/recording/encoder_pcm.cpp
new file mode 100644
index 0000000..27c671b
--- /dev/null
+++ b/kradio3/plugins/recording/encoder_pcm.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+ encoder_pcm.cpp
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 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 "encoder_pcm.h"
+
+
+#include <klocale.h>
+
+RecordingEncodingPCM::RecordingEncodingPCM(QObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const QString &filename)
+ : RecordingEncoding(parent, ssid, cfg, rs, filename),
+ m_output(NULL)
+{
+ m_config.m_SoundFormat.m_Encoding = "raw";
+ openOutput(filename);
+}
+
+
+RecordingEncodingPCM::~RecordingEncodingPCM()
+{
+ closeOutput();
+}
+
+
+
+void RecordingEncodingPCM::encode(const char *buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size)
+{
+ if (m_error)
+ return;
+ m_encodedSize += buffer_size;
+
+ export_buffer = const_cast<char*>(buffer);
+ export_buffer_size = buffer_size;
+ int err = sf_write_raw(m_output, const_cast<char*>(buffer), buffer_size);
+
+ if (err != (int)buffer_size) {
+ m_error = true;
+ m_errorString += i18n("Error %1 writing output. ").arg(QString().setNum(err));
+ }
+}
+
+
+bool RecordingEncodingPCM::openOutput(const QString &output)
+{
+ SF_INFO sinfo;
+ m_config.getSoundFileInfo(sinfo, false);
+ m_output = sf_open(output.ascii(), SFM_WRITE, &sinfo);
+
+ if (!m_output) {
+ m_error = true;
+ m_errorString += i18n("Cannot open output file %1. ").arg(output);
+ }
+ return !m_error;
+}
+
+
+void RecordingEncodingPCM::closeOutput()
+{
+ if (m_output) sf_close (m_output);
+ m_output = NULL;
+}
+
+
diff --git a/kradio3/plugins/recording/encoder_pcm.h b/kradio3/plugins/recording/encoder_pcm.h
new file mode 100644
index 0000000..e768bba
--- /dev/null
+++ b/kradio3/plugins/recording/encoder_pcm.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ encoder_pcm.h
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_PCM_H
+#define KRADIO_RECORDING_ENCODER_PCM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "encoder.h"
+
+#include <sndfile.h>
+
+class RecordingEncodingPCM : public RecordingEncoding
+{
+public:
+ RecordingEncodingPCM(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename);
+ virtual ~RecordingEncodingPCM();
+
+ bool openOutput(const QString &outputFile);
+ void closeOutput();
+
+protected:
+ void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size);
+
+
+ SNDFILE *m_output;
+};
+
+
+#endif
diff --git a/kradio3/plugins/recording/icons/Makefile.am b/kradio3/plugins/recording/icons/Makefile.am
new file mode 100644
index 0000000..b3f2583
--- /dev/null
+++ b/kradio3/plugins/recording/icons/Makefile.am
@@ -0,0 +1,2 @@
+icons_ICON = AUTO
+iconsdir = $(kde_datadir)/kradio/icons
diff --git a/kradio3/plugins/recording/icons/hi16-action-kradio_record.png b/kradio3/plugins/recording/icons/hi16-action-kradio_record.png
new file mode 100644
index 0000000..a9e4d3c
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi16-action-kradio_record.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi16-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi16-app-kradio_plus_rec.png
new file mode 100644
index 0000000..11a9395
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi16-app-kradio_plus_rec.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi22-action-kradio_record.png b/kradio3/plugins/recording/icons/hi22-action-kradio_record.png
new file mode 100644
index 0000000..bf57538
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi22-action-kradio_record.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi22-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi22-app-kradio_plus_rec.png
new file mode 100644
index 0000000..d17e9db
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi22-app-kradio_plus_rec.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi256-action-kradio_record.png b/kradio3/plugins/recording/icons/hi256-action-kradio_record.png
new file mode 100644
index 0000000..a122d45
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi256-action-kradio_record.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi32-action-kradio_record.png b/kradio3/plugins/recording/icons/hi32-action-kradio_record.png
new file mode 100644
index 0000000..117202c
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi32-action-kradio_record.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi32-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi32-app-kradio_plus_rec.png
new file mode 100644
index 0000000..436746e
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi32-app-kradio_plus_rec.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi48-action-kradio_record.png b/kradio3/plugins/recording/icons/hi48-action-kradio_record.png
new file mode 100644
index 0000000..5a0c38d
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi48-action-kradio_record.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi48-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi48-app-kradio_plus_rec.png
new file mode 100644
index 0000000..20388ee
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi48-app-kradio_plus_rec.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi64-action-kradio_record.png b/kradio3/plugins/recording/icons/hi64-action-kradio_record.png
new file mode 100644
index 0000000..28d354d
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi64-action-kradio_record.png
Binary files differ
diff --git a/kradio3/plugins/recording/icons/hi64-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi64-app-kradio_plus_rec.png
new file mode 100644
index 0000000..7240ed2
--- /dev/null
+++ b/kradio3/plugins/recording/icons/hi64-app-kradio_plus_rec.png
Binary files differ
diff --git a/kradio3/plugins/recording/po/Makefile.am b/kradio3/plugins/recording/po/Makefile.am
new file mode 100644
index 0000000..80443c3
--- /dev/null
+++ b/kradio3/plugins/recording/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-recording
+POFILES = AUTO
diff --git a/kradio3/plugins/recording/po/de.po b/kradio3/plugins/recording/po/de.po
new file mode 100644
index 0000000..7368347
--- /dev/null
+++ b/kradio3/plugins/recording/po/de.po
@@ -0,0 +1,435 @@
+# translation of de.po to
+# translation of kradio-recording.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-06 00:57+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file recording-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:117 recording-configuration-ui.cpp:244
+#, no-c-format
+msgid "RecordingConfigurationUI"
+msgstr "RecordingConfigurationUI"
+
+#. i18n: file recording-configuration-ui.ui line 34
+#: rc.cpp:6 rc.cpp:120 recording-configuration-ui.cpp:256
+#, no-c-format
+msgid "Output"
+msgstr "Ausgabe"
+
+#. i18n: file recording-configuration-ui.ui line 138
+#: rc.cpp:9 rc.cpp:123 recording-configuration-ui.cpp:245
+#, no-c-format
+msgid "MP3 Quality(0 - high, 9 - low)"
+msgstr "MP3 Qualität(0 - hoch, 9 - niedrig)"
+
+#. i18n: file recording-configuration-ui.ui line 149
+#: rc.cpp:12 rc.cpp:126 recording-configuration-ui.cpp:247
+#, no-c-format
+msgid "raw pcm output (.raw)"
+msgstr "reine PCM-Ausgabe (.raw)"
+
+#. i18n: file recording-configuration-ui.ui line 154
+#: rc.cpp:15 rc.cpp:129 recording-configuration-ui.cpp:248
+#, no-c-format
+msgid "Microsoft Wave (.wav)"
+msgstr "Microsoft Wave (.wav)"
+
+#. i18n: file recording-configuration-ui.ui line 159
+#: rc.cpp:18 rc.cpp:132 recording-configuration-ui.cpp:249
+#, no-c-format
+msgid "Apple/SGI (.aiff)"
+msgstr "Apple/SGI (.aiff)"
+
+#. i18n: file recording-configuration-ui.ui line 164
+#: rc.cpp:21 rc.cpp:135 recording-configuration-ui.cpp:250
+#, no-c-format
+msgid "Sun/NeXT (.au)"
+msgstr "Sun/NeXT (.au)"
+
+#. i18n: file recording-configuration-ui.ui line 169
+#: rc.cpp:24 rc.cpp:138 recording-configuration-ui.cpp:251
+#, no-c-format
+msgid "MP3 Compressed (.mp3)"
+msgstr "MP3 komprimiert (.mp3)"
+
+#. i18n: file recording-configuration-ui.ui line 174
+#: rc.cpp:27 rc.cpp:141 recording-configuration-ui.cpp:252
+#, no-c-format
+msgid "Ogg/Vorbis Compressed (.ogg)"
+msgstr "Ogg/Vorbis komprimiert (.ogg)"
+
+#. i18n: file recording-configuration-ui.ui line 194
+#: rc.cpp:30 rc.cpp:144 recording-configuration-ui.cpp:253
+#, no-c-format
+msgid "Recording Directory"
+msgstr "Aufnahme-Verzeichnis"
+
+#. i18n: file recording-configuration-ui.ui line 202
+#: rc.cpp:33 rc.cpp:147 recording-configuration-ui.cpp:254
+#, no-c-format
+msgid "File Format"
+msgstr "Dateiformat"
+
+#. i18n: file recording-configuration-ui.ui line 210
+#: rc.cpp:36 rc.cpp:150 recording-configuration-ui.cpp:255
+#, no-c-format
+msgid "Ogg Quality(0 - low, 9 - high)"
+msgstr "Ogg Qualität(0 - niedrig, 9 - hoch)"
+
+#. i18n: file recording-configuration-ui.ui line 239
+#: rc.cpp:39 rc.cpp:153 recording-configuration-ui.cpp:278
+#, no-c-format
+msgid "I&nput"
+msgstr "Quelle"
+
+#. i18n: file recording-configuration-ui.ui line 276
+#: rc.cpp:42 rc.cpp:156 recording-configuration-ui.cpp:258
+#, no-c-format
+msgid "48000"
+msgstr "48000"
+
+#. i18n: file recording-configuration-ui.ui line 281
+#: rc.cpp:45 rc.cpp:159 recording-configuration-ui.cpp:259
+#, no-c-format
+msgid "44100"
+msgstr "44100"
+
+#. i18n: file recording-configuration-ui.ui line 286
+#: rc.cpp:48 rc.cpp:162 recording-configuration-ui.cpp:260
+#, no-c-format
+msgid "22050"
+msgstr "22050"
+
+#. i18n: file recording-configuration-ui.ui line 291
+#: rc.cpp:51 rc.cpp:165 recording-configuration-ui.cpp:261
+#, no-c-format
+msgid "11025"
+msgstr "11025"
+
+#. i18n: file recording-configuration-ui.ui line 311
+#: rc.cpp:54 rc.cpp:168 recording-configuration-ui.cpp:262
+#, no-c-format
+msgid "Endianess"
+msgstr "Byte-Reihenfolge"
+
+#. i18n: file recording-configuration-ui.ui line 334
+#: rc.cpp:57 rc.cpp:171 recording-configuration-ui.cpp:264
+#, no-c-format
+msgid "Stereo"
+msgstr "Stereo"
+
+#. i18n: file recording-configuration-ui.ui line 339
+#: rc.cpp:60 rc.cpp:174 recording-configuration-ui.cpp:265
+#, no-c-format
+msgid "Mono"
+msgstr "Mono"
+
+#. i18n: file recording-configuration-ui.ui line 359
+#: rc.cpp:63 rc.cpp:177 recording-configuration-ui.cpp:266
+#: recording-monitor.cpp:53
+#, no-c-format
+msgid "Sample Rate"
+msgstr "Abtastrate"
+
+#. i18n: file recording-configuration-ui.ui line 365
+#: rc.cpp:66 rc.cpp:180 recording-configuration-ui.cpp:268
+#, no-c-format
+msgid "Little Endian"
+msgstr "Little Endian"
+
+#. i18n: file recording-configuration-ui.ui line 370
+#: rc.cpp:69 rc.cpp:183 recording-configuration-ui.cpp:269
+#, no-c-format
+msgid "Big Endian"
+msgstr "Big Endian"
+
+#. i18n: file recording-configuration-ui.ui line 388
+#: rc.cpp:72 rc.cpp:186 recording-configuration-ui.cpp:271
+#, no-c-format
+msgid "16"
+msgstr "16"
+
+#. i18n: file recording-configuration-ui.ui line 393
+#: rc.cpp:75 rc.cpp:189 recording-configuration-ui.cpp:272
+#, no-c-format
+msgid "8"
+msgstr "8"
+
+#. i18n: file recording-configuration-ui.ui line 413
+#: rc.cpp:78 rc.cpp:192 recording-configuration-ui.cpp:273
+#, no-c-format
+msgid "Channels"
+msgstr "Kanäle"
+
+#. i18n: file recording-configuration-ui.ui line 421
+#: rc.cpp:81 rc.cpp:195 recording-configuration-ui.cpp:274
+#, no-c-format
+msgid "Sample Bits"
+msgstr "Quantisierungs-Bits"
+
+#. i18n: file recording-configuration-ui.ui line 427
+#: rc.cpp:84 rc.cpp:198 recording-configuration-ui.cpp:276
+#, no-c-format
+msgid "Signed"
+msgstr "Vorzeichenbehaftet"
+
+#. i18n: file recording-configuration-ui.ui line 432
+#: rc.cpp:87 rc.cpp:201 recording-configuration-ui.cpp:277
+#, no-c-format
+msgid "Unsigned"
+msgstr "Vorzeichenlos"
+
+#. i18n: file recording-configuration-ui.ui line 490
+#: rc.cpp:90 rc.cpp:204 recording-configuration-ui.cpp:282
+#, no-c-format
+msgid "&Buffers"
+msgstr "&Puffer"
+
+#. i18n: file recording-configuration-ui.ui line 512
+#: rc.cpp:93 rc.cpp:207 recording-configuration-ui.cpp:279
+#, no-c-format
+msgid " kB"
+msgstr " kB"
+
+#. i18n: file recording-configuration-ui.ui line 532
+#: rc.cpp:96 rc.cpp:210 recording-configuration-ui.cpp:280
+#, no-c-format
+msgid "Encoding Buffer Size"
+msgstr "Codierungs-Puffergröße"
+
+#. i18n: file recording-configuration-ui.ui line 551
+#: rc.cpp:99 rc.cpp:213 recording-configuration-ui.cpp:281
+#, no-c-format
+msgid "Number of Buffers"
+msgstr "Anzahl der Puffer"
+
+#. i18n: file recording-configuration-ui.ui line 580
+#: rc.cpp:102 rc.cpp:216 recording-configuration-ui.cpp:287
+#, no-c-format
+msgid "Pre-Recordin&g"
+msgstr "Aufnahme&vorlaufs"
+
+#. i18n: file recording-configuration-ui.ui line 610
+#: rc.cpp:105 rc.cpp:219 recording-configuration-ui.cpp:283
+#, no-c-format
+msgid "E&nable"
+msgstr "&Einschalten"
+
+#. i18n: file recording-configuration-ui.ui line 613
+#: rc.cpp:108 rc.cpp:222 recording-configuration-ui.cpp:284
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#. i18n: file recording-configuration-ui.ui line 651
+#: rc.cpp:111 rc.cpp:225 recording-configuration-ui.cpp:285
+#, no-c-format
+msgid "PreRecording Time"
+msgstr "Dauer des Aufnahmevorlaufs"
+
+#. i18n: file recording-configuration-ui.ui line 662
+#: rc.cpp:114 rc.cpp:228 recording-configuration-ui.cpp:286
+#, no-c-format
+msgid " s"
+msgstr " s"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: encoder_mp3.cpp:79 encoder_mp3.cpp:189
+msgid "Error %1 while encoding mp3. "
+msgstr "Fehler %1 beim Codieren des MP3-Streams. "
+
+#: encoder_mp3.cpp:89 encoder_mp3.cpp:194 encoder_pcm.cpp:53
+msgid "Error %1 writing output. "
+msgstr "Fehler %1 beim Schreiben der Ausgabedatei. "
+
+#: encoder_mp3.cpp:106
+msgid "Cannot initialize lalibmp3lame. "
+msgstr "Die Funktionsbibliothek libmp3lame kann nicht initialisiert werden. "
+
+#: encoder_mp3.cpp:123
+msgid "Cannot initialize libmp3lame parameters. "
+msgstr ""
+"Die Parameter der Funktionsbibliothek libmp3lame konnten nicht initialisiert "
+"werden."
+
+#: encoder_mp3.cpp:130
+msgid "Recorded by KRadio"
+msgstr "Aufzeichnung durch KRadio"
+
+#: encoder_mp3.cpp:143 encoder_pcm.cpp:66
+msgid "Cannot open output file %1. "
+msgstr "Die Ausgabedatei %1 kann nicht geöffnet werden. "
+
+#: encoder_mp3.cpp:156
+msgid "Cannot allocate buffers for mp3 encoding. "
+msgstr ""
+"Die Puffer für das Codieren des MP3-Streams konnten nicht angelegt werden. "
+
+#: encoder_ogg.cpp:94
+msgid "Failed writing data to ogg/vorbis output stream. "
+msgstr "Das schreiben der Ogg/Vorbis-Daten schlug fehl. "
+
+#: encoder_ogg.cpp:136
+msgid "Cannot open Ogg/Vorbis output file %1. "
+msgstr "Die Ogg/Vorbis-Ausgabedatei %1 konnte nicht geöffnet werden. "
+
+#: encoder_ogg.cpp:149
+msgid "Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n"
+msgstr ""
+"Die Initialisierung des Ogg/Vorbis-Modes schlug fehl: Ungültiger Qualitäts-"
+"Parameter\n"
+
+#: encoder_ogg.cpp:200
+msgid "Failed writing Ogg/Vorbis header to output stream\n"
+msgstr "Das Schreiben der Ogg/Vorbis-Kopfdaten der Ausgabedatei schlug fehl\n"
+
+#: recording-datamonitor.cpp:174 recording-datamonitor.cpp:179
+msgid "%1 dB"
+msgstr "%1 dB"
+
+#: recording-monitor.cpp:34
+msgid "Recording Monitor"
+msgstr "Aufnahme-Überwachung"
+
+#: recording-monitor.cpp:38 recording.cpp:47
+msgid "KRadio Recording Monitor"
+msgstr "KRadio Aufnahme-Überwachung"
+
+#: recording-monitor.cpp:43
+msgid "SoundStream"
+msgstr "Aufnahmedatenstrom"
+
+#: recording-monitor.cpp:45
+msgid "Status"
+msgstr "Status"
+
+#: recording-monitor.cpp:46 recording-monitor.cpp:48 recording-monitor.cpp:50
+#: recording-monitor.cpp:52 recording-monitor.cpp:54
+msgid "<undefined>"
+msgstr "<undefiniert>"
+
+#: recording-monitor.cpp:47
+msgid "Recording File"
+msgstr "Aufnahmedatei"
+
+#: recording-monitor.cpp:49
+msgid "File Size"
+msgstr "Dateigröße"
+
+#: recording-monitor.cpp:51
+msgid "Recording Time"
+msgstr "Aufnahmezeit"
+
+#: recording-monitor.cpp:57 recording-monitor.cpp:393
+#: recording-monitor.cpp:396
+msgid "&Record"
+msgstr "&Aufnehmen"
+
+#: recording-monitor.cpp:74 recording-monitor.cpp:118
+#: recording-monitor.cpp:141
+msgid "nothing"
+msgstr "nichts"
+
+#: recording-monitor.cpp:339
+msgid "%1 Byte"
+msgstr "%1 Byte"
+
+#: recording-monitor.cpp:340
+msgid "%1 kB"
+msgstr "%1 kB"
+
+#: recording-monitor.cpp:341
+msgid "%1 MB"
+msgstr "%1 MB"
+
+#: recording-monitor.cpp:342
+msgid "%1 GB"
+msgstr "%1 GB"
+
+#: recording-monitor.cpp:345
+msgid "%1 Hz"
+msgstr "%1 Hz"
+
+#: recording-monitor.cpp:393
+msgid "&Stop Recording"
+msgstr "Aufnahme anhalten"
+
+#: recording.cpp:46 recording.cpp:54
+msgid "KRadio Recording Plugin"
+msgstr "KRadio Aufnahme-Plugin"
+
+#: recording.cpp:131 recording.cpp:132
+msgid "Recording"
+msgstr "Aufnahme"
+
+#: recording.cpp:360
+msgid "start capture not handled"
+msgstr "Der Aufnahmestart wurde ignoriert"
+
+#: recording.cpp:367
+msgid "Recording starting"
+msgstr "Die Aufnahme wird gestartet"
+
+#: recording.cpp:369
+msgid "starting encoding thread failed"
+msgstr "Das Starten des Aufnahme-Threads schlug fehl"
+
+#: recording.cpp:451
+msgid "could not read suffient data"
+msgstr "es konnten nicht ausreichend Daten gelesen werden"
+
+#: recording.cpp:482
+msgid ""
+"Encoder input buffer overflow (buffer configuration problem?). Skipped %1 "
+"input bytes"
+msgstr ""
+"Pufferüberlauf des Aufnahmepuffers des Kodierers/Komprimierers (Fehlerhafte "
+"Konfiguration der Puffer?). Es wurden %1 Bytes ignoriert."
+
+#: recording.cpp:544
+msgid "Recording::outputFile: "
+msgstr "Aufnahme::Ausgabedatei: "
+
+#: recording.cpp:595
+msgid "The encoding thread did not finish. It will be killed now."
+msgstr ""
+"Der Codierungs-Thread beendete sich nicht selber. Er wird jetzt mit roher "
+"Gewalt beendet."
+
+#: recording.cpp:600
+msgid "Waiting for encoding thread to terminate."
+msgstr "Warte auf die Beendigung des Codierungs-Threads."
+
+#: recording.cpp:619
+msgid "Recording stopped"
+msgstr "Die Aufnahme wurde beendet"
+
+#: recording.cpp:652
+msgid ""
+"Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes"
+msgstr ""
+"Recording::notifySoundStreamData(Kodierte Daten): Die Empfängermodule "
+"übersprangen %1 Bytess"
diff --git a/kradio3/plugins/recording/po/ru.po b/kradio3/plugins/recording/po/ru.po
new file mode 100644
index 0000000..293e22b
--- /dev/null
+++ b/kradio3/plugins/recording/po/ru.po
@@ -0,0 +1,432 @@
+# translation of ru.po to
+# translation of kradio-recording.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-08 12:35+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file recording-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:117 recording-configuration-ui.cpp:244
+#, no-c-format
+msgid "RecordingConfigurationUI"
+msgstr "RecordingConfigurationUI"
+
+#. i18n: file recording-configuration-ui.ui line 34
+#: rc.cpp:6 rc.cpp:120 recording-configuration-ui.cpp:256
+#, no-c-format
+msgid "Output"
+msgstr "Выход"
+
+#. i18n: file recording-configuration-ui.ui line 138
+#: rc.cpp:9 rc.cpp:123 recording-configuration-ui.cpp:245
+#, no-c-format
+msgid "MP3 Quality(0 - high, 9 - low)"
+msgstr "Качество MP3 (0 — высокое, 9 — низкое)"
+
+#. i18n: file recording-configuration-ui.ui line 149
+#: rc.cpp:12 rc.cpp:126 recording-configuration-ui.cpp:247
+#, no-c-format
+msgid "raw pcm output (.raw)"
+msgstr "Неформатированный вывод (.raw)"
+
+#. i18n: file recording-configuration-ui.ui line 154
+#: rc.cpp:15 rc.cpp:129 recording-configuration-ui.cpp:248
+#, no-c-format
+msgid "Microsoft Wave (.wav)"
+msgstr "Microsoft Wave (.wav)"
+
+#. i18n: file recording-configuration-ui.ui line 159
+#: rc.cpp:18 rc.cpp:132 recording-configuration-ui.cpp:249
+#, no-c-format
+msgid "Apple/SGI (.aiff)"
+msgstr "Apple/SGI (.aiff)"
+
+#. i18n: file recording-configuration-ui.ui line 164
+#: rc.cpp:21 rc.cpp:135 recording-configuration-ui.cpp:250
+#, no-c-format
+msgid "Sun/NeXT (.au)"
+msgstr "Sun/NeXT (.au)"
+
+#. i18n: file recording-configuration-ui.ui line 169
+#: rc.cpp:24 rc.cpp:138 recording-configuration-ui.cpp:251
+#, no-c-format
+msgid "MP3 Compressed (.mp3)"
+msgstr "Сжатый MP3 (.mp3)"
+
+#. i18n: file recording-configuration-ui.ui line 174
+#: rc.cpp:27 rc.cpp:141 recording-configuration-ui.cpp:252
+#, no-c-format
+msgid "Ogg/Vorbis Compressed (.ogg)"
+msgstr "Сжатый Ogg Vorbis (.ogg)"
+
+#. i18n: file recording-configuration-ui.ui line 194
+#: rc.cpp:30 rc.cpp:144 recording-configuration-ui.cpp:253
+#, no-c-format
+msgid "Recording Directory"
+msgstr "Каталог для сохранения"
+
+#. i18n: file recording-configuration-ui.ui line 202
+#: rc.cpp:33 rc.cpp:147 recording-configuration-ui.cpp:254
+#, no-c-format
+msgid "File Format"
+msgstr "Формат файла"
+
+#. i18n: file recording-configuration-ui.ui line 210
+#: rc.cpp:36 rc.cpp:150 recording-configuration-ui.cpp:255
+#, no-c-format
+msgid "Ogg Quality(0 - low, 9 - high)"
+msgstr "Качество Ogg (0 — ниже, 9 — выше)"
+
+#. i18n: file recording-configuration-ui.ui line 239
+#: rc.cpp:39 rc.cpp:153 recording-configuration-ui.cpp:278
+#, no-c-format
+msgid "I&nput"
+msgstr "В&вод"
+
+#. i18n: file recording-configuration-ui.ui line 276
+#: rc.cpp:42 rc.cpp:156 recording-configuration-ui.cpp:258
+#, no-c-format
+msgid "48000"
+msgstr "48000"
+
+#. i18n: file recording-configuration-ui.ui line 281
+#: rc.cpp:45 rc.cpp:159 recording-configuration-ui.cpp:259
+#, no-c-format
+msgid "44100"
+msgstr "44100"
+
+#. i18n: file recording-configuration-ui.ui line 286
+#: rc.cpp:48 rc.cpp:162 recording-configuration-ui.cpp:260
+#, no-c-format
+msgid "22050"
+msgstr "22050"
+
+#. i18n: file recording-configuration-ui.ui line 291
+#: rc.cpp:51 rc.cpp:165 recording-configuration-ui.cpp:261
+#, no-c-format
+msgid "11025"
+msgstr "11025"
+
+#. i18n: file recording-configuration-ui.ui line 311
+#: rc.cpp:54 rc.cpp:168 recording-configuration-ui.cpp:262
+#, no-c-format
+msgid "Endianess"
+msgstr "Порядок байтов"
+
+#. i18n: file recording-configuration-ui.ui line 334
+#: rc.cpp:57 rc.cpp:171 recording-configuration-ui.cpp:264
+#, no-c-format
+msgid "Stereo"
+msgstr "2 (Стерео)"
+
+#. i18n: file recording-configuration-ui.ui line 339
+#: rc.cpp:60 rc.cpp:174 recording-configuration-ui.cpp:265
+#, no-c-format
+msgid "Mono"
+msgstr "1 (Моно)"
+
+#. i18n: file recording-configuration-ui.ui line 359
+#: rc.cpp:63 rc.cpp:177 recording-configuration-ui.cpp:266
+#: recording-monitor.cpp:53
+#, no-c-format
+msgid "Sample Rate"
+msgstr "Частота дискретизации"
+
+#. i18n: file recording-configuration-ui.ui line 365
+#: rc.cpp:66 rc.cpp:180 recording-configuration-ui.cpp:268
+#, no-c-format
+msgid "Little Endian"
+msgstr "Little Endian"
+
+#. i18n: file recording-configuration-ui.ui line 370
+#: rc.cpp:69 rc.cpp:183 recording-configuration-ui.cpp:269
+#, fuzzy, no-c-format
+msgid "Big Endian"
+msgstr "Big Endian"
+
+#. i18n: file recording-configuration-ui.ui line 388
+#: rc.cpp:72 rc.cpp:186 recording-configuration-ui.cpp:271
+#, no-c-format
+msgid "16"
+msgstr "16"
+
+#. i18n: file recording-configuration-ui.ui line 393
+#: rc.cpp:75 rc.cpp:189 recording-configuration-ui.cpp:272
+#, no-c-format
+msgid "8"
+msgstr "8"
+
+#. i18n: file recording-configuration-ui.ui line 413
+#: rc.cpp:78 rc.cpp:192 recording-configuration-ui.cpp:273
+#, no-c-format
+msgid "Channels"
+msgstr "Число каналов"
+
+#. i18n: file recording-configuration-ui.ui line 421
+#: rc.cpp:81 rc.cpp:195 recording-configuration-ui.cpp:274
+#, no-c-format
+msgid "Sample Bits"
+msgstr "Бит на элемент выборки"
+
+#. i18n: file recording-configuration-ui.ui line 427
+#: rc.cpp:84 rc.cpp:198 recording-configuration-ui.cpp:276
+#, no-c-format
+msgid "Signed"
+msgstr "Со знаком"
+
+#. i18n: file recording-configuration-ui.ui line 432
+#: rc.cpp:87 rc.cpp:201 recording-configuration-ui.cpp:277
+#, no-c-format
+msgid "Unsigned"
+msgstr "Без знака"
+
+#. i18n: file recording-configuration-ui.ui line 490
+#: rc.cpp:90 rc.cpp:204 recording-configuration-ui.cpp:282
+#, no-c-format
+msgid "&Buffers"
+msgstr "&Буферы"
+
+#. i18n: file recording-configuration-ui.ui line 512
+#: rc.cpp:93 rc.cpp:207 recording-configuration-ui.cpp:279
+#, no-c-format
+msgid " kB"
+msgstr " кБ"
+
+#. i18n: file recording-configuration-ui.ui line 532
+#: rc.cpp:96 rc.cpp:210 recording-configuration-ui.cpp:280
+#, no-c-format
+msgid "Encoding Buffer Size"
+msgstr "Размер буфера для записи"
+
+#. i18n: file recording-configuration-ui.ui line 551
+#: rc.cpp:99 rc.cpp:213 recording-configuration-ui.cpp:281
+#, no-c-format
+msgid "Number of Buffers"
+msgstr "Количество буферов"
+
+#. i18n: file recording-configuration-ui.ui line 580
+#: rc.cpp:102 rc.cpp:216 recording-configuration-ui.cpp:287
+#, no-c-format
+msgid "Pre-Recordin&g"
+msgstr "&Упреждающая запись"
+
+#. i18n: file recording-configuration-ui.ui line 610
+#: rc.cpp:105 rc.cpp:219 recording-configuration-ui.cpp:283
+#, no-c-format
+msgid "E&nable"
+msgstr "Включить"
+
+#. i18n: file recording-configuration-ui.ui line 613
+#: rc.cpp:108 rc.cpp:222 recording-configuration-ui.cpp:284
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#. i18n: file recording-configuration-ui.ui line 651
+#: rc.cpp:111 rc.cpp:225 recording-configuration-ui.cpp:285
+#, no-c-format
+msgid "PreRecording Time"
+msgstr "Упреждение"
+
+#. i18n: file recording-configuration-ui.ui line 662
+#: rc.cpp:114 rc.cpp:228 recording-configuration-ui.cpp:286
+#, no-c-format
+msgid " s"
+msgstr " с"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: encoder_mp3.cpp:79 encoder_mp3.cpp:189
+msgid "Error %1 while encoding mp3. "
+msgstr "При кодировании MP3 произошла ошибка: %1. "
+
+#: encoder_mp3.cpp:89 encoder_mp3.cpp:194 encoder_pcm.cpp:53
+msgid "Error %1 writing output. "
+msgstr "Во время записи произошла ошибка: %1"
+
+#: encoder_mp3.cpp:106
+msgid "Cannot initialize lalibmp3lame. "
+msgstr ""
+"Не могу инициализировать lalibmp3lame — необходимо для кодирования в MP3."
+
+#: encoder_mp3.cpp:123
+msgid "Cannot initialize libmp3lame parameters. "
+msgstr ""
+"Не могу инициализировать параметры libmp3lame — необходимо для кодирования в "
+"MP3."
+
+#: encoder_mp3.cpp:130
+msgid "Recorded by KRadio"
+msgstr "Запись KRadio"
+
+#: encoder_mp3.cpp:143 encoder_pcm.cpp:66
+msgid "Cannot open output file %1. "
+msgstr "Не могу открыть выходной файл %1. "
+
+#: encoder_mp3.cpp:156
+msgid "Cannot allocate buffers for mp3 encoding. "
+msgstr "Не могу разместить в памяти буферы для кодирования MP3."
+
+#: encoder_ogg.cpp:94
+msgid "Failed writing data to ogg/vorbis output stream. "
+msgstr "Ошибка записи данных в выходной поток ogg/vorbis. "
+
+#: encoder_ogg.cpp:136
+msgid "Cannot open Ogg/Vorbis output file %1. "
+msgstr "Не могу открыть выходной файл Ogg/Vorbis \"%1\". "
+
+#: encoder_ogg.cpp:149
+msgid "Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n"
+msgstr ""
+"Инициализация режима Ogg/Vorbis не удалась: качество записи указано неверно\n"
+
+#: encoder_ogg.cpp:200
+msgid "Failed writing Ogg/Vorbis header to output stream\n"
+msgstr "Ошибка записи заголовка Ogg/Vorbis в выходной поток\n"
+
+#: recording-datamonitor.cpp:174 recording-datamonitor.cpp:179
+msgid "%1 dB"
+msgstr "%1 дБ"
+
+#: recording-monitor.cpp:34
+msgid "Recording Monitor"
+msgstr "Монитор записи"
+
+#: recording-monitor.cpp:38 recording.cpp:47
+msgid "KRadio Recording Monitor"
+msgstr "Монитор записи для KRadio"
+
+#: recording-monitor.cpp:43
+msgid "SoundStream"
+msgstr "Источник"
+
+#: recording-monitor.cpp:45
+msgid "Status"
+msgstr "Состояние"
+
+#: recording-monitor.cpp:46 recording-monitor.cpp:48 recording-monitor.cpp:50
+#: recording-monitor.cpp:52 recording-monitor.cpp:54
+msgid "<undefined>"
+msgstr "<не определено>"
+
+#: recording-monitor.cpp:47
+msgid "Recording File"
+msgstr "Файл"
+
+#: recording-monitor.cpp:49
+msgid "File Size"
+msgstr "Размер файла"
+
+#: recording-monitor.cpp:51
+msgid "Recording Time"
+msgstr "Длительность записи"
+
+#: recording-monitor.cpp:57 recording-monitor.cpp:393
+#: recording-monitor.cpp:396
+msgid "&Record"
+msgstr "&Начать запись"
+
+#: recording-monitor.cpp:74 recording-monitor.cpp:118
+#: recording-monitor.cpp:141
+msgid "nothing"
+msgstr "(нет)"
+
+#: recording-monitor.cpp:339
+msgid "%1 Byte"
+msgstr "%1 байт"
+
+#: recording-monitor.cpp:340
+msgid "%1 kB"
+msgstr "%1 кБ"
+
+#: recording-monitor.cpp:341
+msgid "%1 MB"
+msgstr "%1 МБ"
+
+#: recording-monitor.cpp:342
+msgid "%1 GB"
+msgstr "%1 ГБ"
+
+#: recording-monitor.cpp:345
+msgid "%1 Hz"
+msgstr "%1 Гц"
+
+#: recording-monitor.cpp:393
+msgid "&Stop Recording"
+msgstr "&Остановить запись"
+
+#: recording.cpp:46 recording.cpp:54
+msgid "KRadio Recording Plugin"
+msgstr "Модуль записи звука для KRadio"
+
+#: recording.cpp:131 recording.cpp:132
+msgid "Recording"
+msgstr "Запись"
+
+#: recording.cpp:360
+msgid "start capture not handled"
+msgstr ""
+
+#: recording.cpp:367
+msgid "Recording starting"
+msgstr "Запись запущена"
+
+#: recording.cpp:369
+msgid "starting encoding thread failed"
+msgstr "Не смог запустить процесс кодирования"
+
+#: recording.cpp:451
+msgid "could not read suffient data"
+msgstr "Не смог прочесть достаточно данных"
+
+#: recording.cpp:482
+msgid ""
+"Encoder input buffer overflow (buffer configuration problem?). Skipped %1 "
+"input bytes"
+msgstr ""
+"Переполнение на входе кодировщика (вероятно, неправильно настроен буфер). "
+"Пропускаю %1 байт на входе."
+
+#: recording.cpp:544
+msgid "Recording::outputFile: "
+msgstr "Recording::outputFile (выходной файл записи):"
+
+#: recording.cpp:595
+msgid "The encoding thread did not finish. It will be killed now."
+msgstr "Нить кодировщика не завершилась. Процесс будет уничтожен."
+
+#: recording.cpp:600
+msgid "Waiting for encoding thread to terminate."
+msgstr "Жду завершения нити кодировщика"
+
+#: recording.cpp:619
+#, fuzzy
+msgid "Recording stopped"
+msgstr "Запись заершена"
+
+#: recording.cpp:652
+msgid ""
+"Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes"
+msgstr ""
+"Recording::notifySoundStreamData(encoded data): Приёмник пропустил %1 байт"
diff --git a/kradio3/plugins/recording/reccfg_interfaces.cpp b/kradio3/plugins/recording/reccfg_interfaces.cpp
new file mode 100644
index 0000000..3b5f32f
--- /dev/null
+++ b/kradio3/plugins/recording/reccfg_interfaces.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ reccfg_interfaces.cpp - description
+ -------------------
+ begin : Sun May 01 2005
+ copyright : (C) 2005by 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 <linux/soundcard.h>
+#include "reccfg_interfaces.h"
+
+// IRecCfg
+
+IF_IMPL_SENDER ( IRecCfg::notifyEncoderBufferChanged (size_t BufferSize, size_t BufferCount),
+ noticeEncoderBufferChanged(BufferSize, BufferCount)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifySoundFormatChanged(const SoundFormat &sf),
+ noticeSoundFormatChanged(sf)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyMP3QualityChanged(int q),
+ noticeMP3QualityChanged(q)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyOggQualityChanged(float q),
+ noticeOggQualityChanged(q)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyRecordingDirectoryChanged(const QString &dir),
+ noticeRecordingDirectoryChanged(dir)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyOutputFormatChanged(RecordingConfig::OutputFormat of),
+ noticeOutputFormatChanged(of)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyPreRecordingChanged(bool enable, int seconds),
+ noticePreRecordingChanged(enable, seconds)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyRecordingConfigChanged (const RecordingConfig &cfg),
+ noticeRecordingConfigChanged(cfg)
+ );
+
+// IRecCfgClient
+
+IF_IMPL_SENDER ( IRecCfgClient::sendEncoderBuffer (size_t BufferSize, size_t BufferCount),
+ setEncoderBuffer(BufferSize, BufferCount)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendSoundFormat(const SoundFormat &sf),
+ setSoundFormat(sf)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendMP3Quality(int q),
+ setMP3Quality(q)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendOggQuality(float q),
+ setOggQuality(q)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendRecordingDirectory(const QString &dir),
+ setRecordingDirectory(dir)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendOutputFormat(RecordingConfig::OutputFormat of),
+ setOutputFormat(of)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendPreRecording(bool enable, int seconds),
+ setPreRecording(enable, seconds)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendRecordingConfig(const RecordingConfig &cfg),
+ setRecordingConfig(cfg)
+ );
+
+IF_IMPL_QUERY ( void IRecCfgClient::queryEncoderBuffer(size_t &BufferSize, size_t &BufferCount),
+ getEncoderBuffer(BufferSize, BufferCount),
+
+ );
+
+static SoundFormat defaultSoundFormat;
+IF_IMPL_QUERY ( const SoundFormat &IRecCfgClient::querySoundFormat (),
+ getSoundFormat(),
+ defaultSoundFormat
+ );
+
+IF_IMPL_QUERY ( int IRecCfgClient::queryMP3Quality (),
+ getMP3Quality(),
+ 7
+ );
+
+IF_IMPL_QUERY ( float IRecCfgClient::queryOggQuality (),
+ getOggQuality(),
+ 7
+ );
+
+static QString defaultRecDir("/tmp");
+IF_IMPL_QUERY ( const QString &IRecCfgClient::queryRecordingDirectory(),
+ getRecordingDirectory(),
+ defaultRecDir
+ );
+
+IF_IMPL_QUERY ( RecordingConfig::OutputFormat IRecCfgClient::queryOutputFormat(),
+ getOutputFormat(),
+ RecordingConfig::outputWAV
+ );
+
+IF_IMPL_QUERY ( bool IRecCfgClient::queryPreRecording(int &seconds),
+ getPreRecording(seconds),
+ false
+ );
+
+static RecordingConfig defaultRecConfig;
+IF_IMPL_QUERY ( const RecordingConfig &IRecCfgClient::queryRecordingConfig(),
+ getRecordingConfig(),
+ defaultRecConfig
+ );
+
+void IRecCfgClient::noticeConnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ size_t bs = 0, bc = 0;
+ queryEncoderBuffer(bs, bc);
+ noticeEncoderBufferChanged(bs, bc);
+ noticeSoundFormatChanged(querySoundFormat());
+ noticeMP3QualityChanged (queryMP3Quality());
+ noticeOggQualityChanged (queryOggQuality());
+ noticeRecordingDirectoryChanged(queryRecordingDirectory());
+ noticeOutputFormatChanged(queryOutputFormat());
+ int s = 0;
+ bool e = queryPreRecording(s);
+ noticePreRecordingChanged(e, s);
+ noticeRecordingConfigChanged(queryRecordingConfig());
+}
+
+
+void IRecCfgClient::noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ size_t bs = 0, bc = 0;
+ queryEncoderBuffer(bs, bc);
+ noticeEncoderBufferChanged(bs, bc);
+ noticeSoundFormatChanged(querySoundFormat());
+ noticeMP3QualityChanged (queryMP3Quality());
+ noticeOggQualityChanged (queryOggQuality());
+ noticeRecordingDirectoryChanged(queryRecordingDirectory());
+ noticeOutputFormatChanged(queryOutputFormat());
+ int s = 0;
+ bool e = queryPreRecording(s);
+ noticePreRecordingChanged(e, s);
+ noticeRecordingConfigChanged(queryRecordingConfig());
+}
+
+
diff --git a/kradio3/plugins/recording/reccfg_interfaces.h b/kradio3/plugins/recording/reccfg_interfaces.h
new file mode 100644
index 0000000..907f494
--- /dev/null
+++ b/kradio3/plugins/recording/reccfg_interfaces.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ reccfg_interfaces.h - description
+ -------------------
+ begin : Sun May 01 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECCFG_INTERFACES_H
+#define KRADIO_RECCFG_INTERFACES_H
+
+#include "../../src/include/interfaces.h"
+#include "recording-config.h"
+
+INTERFACE(IRecCfg, IRecCfgClient)
+{
+public:
+ IF_CON_DESTRUCTOR(IRecCfg, -1)
+
+RECEIVERS:
+ IF_RECEIVER( setEncoderBuffer (size_t BufferSize, size_t BufferCount) )
+ IF_RECEIVER( setSoundFormat (const SoundFormat &sf) )
+ IF_RECEIVER( setMP3Quality (int q) )
+ IF_RECEIVER( setOggQuality (float q) )
+ IF_RECEIVER( setRecordingDirectory(const QString &dir) )
+ IF_RECEIVER( setOutputFormat (RecordingConfig::OutputFormat of) )
+ IF_RECEIVER( setPreRecording (bool enable, int seconds) )
+ IF_RECEIVER( setRecordingConfig (const RecordingConfig &cfg) )
+
+SENDERS:
+ IF_SENDER ( notifyEncoderBufferChanged (size_t BufferSize, size_t BufferCount) )
+ IF_SENDER ( notifySoundFormatChanged (const SoundFormat &sf) )
+ IF_SENDER ( notifyMP3QualityChanged (int q) )
+ IF_SENDER ( notifyOggQualityChanged (float q) )
+ IF_SENDER ( notifyRecordingDirectoryChanged(const QString &dir) )
+ IF_SENDER ( notifyOutputFormatChanged (RecordingConfig::OutputFormat of) )
+ IF_SENDER ( notifyPreRecordingChanged (bool enable, int seconds) )
+ IF_SENDER ( notifyRecordingConfigChanged (const RecordingConfig &cfg) )
+
+ANSWERS:
+ IF_ANSWER ( void getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const )
+ IF_ANSWER ( const SoundFormat &getSoundFormat () const )
+ IF_ANSWER ( int getMP3Quality () const )
+ IF_ANSWER ( float getOggQuality () const )
+ IF_ANSWER ( const QString &getRecordingDirectory() const )
+ IF_ANSWER ( RecordingConfig::OutputFormat getOutputFormat() const )
+ IF_ANSWER ( bool getPreRecording(int &seconds) const )
+ IF_ANSWER ( const RecordingConfig &getRecordingConfig() const )
+};
+
+
+
+INTERFACE(IRecCfgClient, IRecCfg)
+{
+public:
+ IF_CON_DESTRUCTOR(IRecCfgClient, 1)
+
+SENDERS:
+ IF_SENDER ( sendEncoderBuffer (size_t BufferSize, size_t BufferCount) )
+ IF_SENDER ( sendSoundFormat (const SoundFormat &sf) )
+ IF_SENDER ( sendMP3Quality (int q) )
+ IF_SENDER ( sendOggQuality (float q) )
+ IF_SENDER ( sendRecordingDirectory(const QString &dir) )
+ IF_SENDER ( sendOutputFormat (RecordingConfig::OutputFormat of) )
+ IF_SENDER ( sendPreRecording (bool enable, int seconds) )
+ IF_SENDER ( sendRecordingConfig (const RecordingConfig &cfg) )
+
+RECEIVERS:
+ IF_RECEIVER( noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount) )
+ IF_RECEIVER( noticeSoundFormatChanged (const SoundFormat &sf) )
+ IF_RECEIVER( noticeMP3QualityChanged (int q) )
+ IF_RECEIVER( noticeOggQualityChanged (float q) )
+ IF_RECEIVER( noticeRecordingDirectoryChanged(const QString &dir) )
+ IF_RECEIVER( noticeOutputFormatChanged (RecordingConfig::OutputFormat of) )
+ IF_RECEIVER( noticePreRecordingChanged (bool enable, int seconds) )
+ IF_RECEIVER( noticeRecordingConfigChanged (const RecordingConfig &cfg) )
+
+QUERIES:
+ IF_QUERY ( void queryEncoderBuffer(size_t &BufferSize, size_t &BufferCount) )
+ IF_QUERY ( const SoundFormat &querySoundFormat () )
+ IF_QUERY ( int queryMP3Quality () )
+ IF_QUERY ( float queryOggQuality () )
+ IF_QUERY ( const QString &queryRecordingDirectory() )
+ IF_QUERY ( RecordingConfig::OutputFormat queryOutputFormat() )
+ IF_QUERY ( bool queryPreRecording(int &seconds) )
+ IF_QUERY ( const RecordingConfig &queryRecordingConfig() )
+
+RECEIVERS:
+ virtual void noticeConnectedI (cmplInterface *, bool /*pointer_valid*/);
+ virtual void noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/);
+};
+
+#endif
diff --git a/kradio3/plugins/recording/recording-config.cpp b/kradio3/plugins/recording/recording-config.cpp
new file mode 100644
index 0000000..131953f
--- /dev/null
+++ b/kradio3/plugins/recording/recording-config.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+ recording-config.cpp - description
+ -------------------
+ begin : Mi Apr 30 2005
+ copyright : (C) 2005 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 "recording-config.h"
+
+#include <sndfile.h>
+
+RecordingConfig::RecordingConfig ()
+: m_EncodeBufferSize(256*1024),
+ m_EncodeBufferCount(3),
+ m_mp3Quality(7),
+ m_oggQuality(1.0),
+ m_Directory("/tmp"),
+ m_OutputFormat(outputWAV),
+ m_PreRecordingEnable (false),
+ m_PreRecordingSeconds(10)
+{
+ checkFormatSettings();
+}
+
+RecordingConfig::RecordingConfig (const QString &directory,
+ OutputFormat of,
+ const SoundFormat &sf, int mp3_q, float ogg_q)
+: m_EncodeBufferSize(256*1024),
+ m_EncodeBufferCount(3),
+ m_SoundFormat(sf),
+ m_mp3Quality(mp3_q),
+ m_oggQuality(ogg_q),
+ m_Directory(directory),
+ m_OutputFormat(of),
+ m_PreRecordingEnable (false),
+ m_PreRecordingSeconds(10)
+{
+ checkFormatSettings();
+}
+
+
+RecordingConfig::RecordingConfig (const RecordingConfig &c)
+ :
+ m_EncodeBufferSize(c.m_EncodeBufferSize),
+ m_EncodeBufferCount(c.m_EncodeBufferCount),
+ m_SoundFormat(c.m_SoundFormat),
+ m_mp3Quality(c.m_mp3Quality),
+ m_oggQuality(c.m_oggQuality),
+ m_Directory(c.m_Directory),
+ m_OutputFormat(c.m_OutputFormat),
+ m_PreRecordingEnable (false),
+ m_PreRecordingSeconds(10)
+{
+ checkFormatSettings();
+}
+
+
+void RecordingConfig::restoreConfig(KConfig *c)
+{
+ m_EncodeBufferSize = c->readNumEntry("encodeBufferSize", 256*1024);
+ m_EncodeBufferCount = c->readNumEntry("encodeBufferCount", 3);
+
+ m_SoundFormat.restoreConfig("", c);
+ m_Directory = c->readEntry("directory", "/tmp");
+ m_mp3Quality = c->readNumEntry("mp3quality", 7);
+ m_oggQuality = c->readDoubleNumEntry("oggquality", 1.0);
+ QString of = c->readEntry("outputFormat", ".wav");
+
+ if (of == ".wav")
+ m_OutputFormat = outputWAV;
+ else if (of == ".aiff")
+ m_OutputFormat = outputAIFF;
+ else if (of == ".au")
+ m_OutputFormat = outputAU;
+#ifdef HAVE_LAME
+ else if (of == ".mp3")
+ m_OutputFormat = outputMP3;
+#endif
+#ifdef HAVE_OGG
+ else if (of == ".ogg")
+ m_OutputFormat = outputOGG;
+#endif
+ else if (of == ".raw")
+ m_OutputFormat = outputRAW;
+
+ // if there was any unknown format
+ else
+ m_OutputFormat = outputWAV;
+
+ m_PreRecordingEnable = c->readBoolEntry("prerecording-enable", false);
+ m_PreRecordingSeconds = c->readNumEntry("prerecording-seconds", 10);
+
+ checkFormatSettings();
+}
+
+
+void RecordingConfig::saveConfig(KConfig *c) const
+{
+ c->writeEntry("encodeBufferSize", m_EncodeBufferSize);
+ c->writeEntry("encodeBufferCount", m_EncodeBufferCount);
+ m_SoundFormat.saveConfig("", c);
+ c->writeEntry("directory", m_Directory);
+ c->writeEntry("mp3quality", m_mp3Quality);
+ c->writeEntry("oggquality", m_oggQuality);
+
+ switch(m_OutputFormat) {
+ case outputWAV: c->writeEntry("outputFormat", ".wav"); break;
+ case outputAIFF: c->writeEntry("outputFormat", ".aiff"); break;
+ case outputAU: c->writeEntry("outputFormat", ".au"); break;
+ case outputMP3: c->writeEntry("outputFormat", ".mp3"); break;
+ case outputOGG: c->writeEntry("outputFormat", ".ogg"); break;
+ case outputRAW: c->writeEntry("outputFormat", ".raw"); break;
+ default: c->writeEntry("outputFormat", ".wav"); break;
+ }
+
+ c->writeEntry("prerecording-enable", m_PreRecordingEnable);
+ c->writeEntry("prerecording-seconds", m_PreRecordingSeconds);
+}
+
+
+void RecordingConfig::getSoundFileInfo(SF_INFO &sinfo, bool input)
+{
+ checkFormatSettings();
+
+ sinfo.samplerate = m_SoundFormat.m_SampleRate;
+ sinfo.channels = m_SoundFormat.m_Channels;
+ sinfo.format = 0;
+ sinfo.seekable = !input;
+
+ // U8 only supported for RAW and WAV
+ if (m_SoundFormat.m_SampleBits == 8) {
+ if ((m_SoundFormat.m_IsSigned &&
+ m_OutputFormat != outputWAV) ||
+ m_OutputFormat == outputAU
+ ) {
+ sinfo.format |= SF_FORMAT_PCM_S8;
+ } else {
+ sinfo.format |= SF_FORMAT_PCM_U8;
+ }
+ }
+ if (m_SoundFormat.m_SampleBits == 16)
+ sinfo.format |= SF_FORMAT_PCM_16;
+
+ if (m_SoundFormat.m_Endianess == LITTLE_ENDIAN)
+ sinfo.format |= SF_ENDIAN_LITTLE;
+ else
+ sinfo.format |= SF_ENDIAN_BIG;
+
+ if (input) {
+ sinfo.format |= SF_FORMAT_RAW;
+ } else {
+ switch (m_OutputFormat) {
+ case outputWAV: sinfo.format |= SF_FORMAT_WAV; break;
+ case outputAIFF: sinfo.format |= SF_FORMAT_AIFF; break;
+ case outputAU: sinfo.format |= SF_FORMAT_AU; break;
+ case outputRAW: sinfo.format |= SF_FORMAT_RAW; break;
+ default: sinfo.format |= SF_FORMAT_WAV; break;
+ }
+ }
+}
+
+
+void RecordingConfig::checkFormatSettings()
+{
+ // correct Endianess and Signs for specific formats
+ switch (m_OutputFormat) {
+ case outputWAV:
+ m_SoundFormat.m_Endianess = LITTLE_ENDIAN;
+ if (m_SoundFormat.m_SampleBits == 8)
+ m_SoundFormat.m_IsSigned = false;
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ case outputAIFF:
+ m_SoundFormat.m_Endianess = BIG_ENDIAN;
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ case outputAU:
+ m_SoundFormat.m_Endianess = BIG_ENDIAN;
+ m_SoundFormat.m_IsSigned = true;
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ case outputMP3:
+ m_SoundFormat.m_IsSigned = true;
+ m_SoundFormat.m_SampleBits = 16;
+ break;
+ case outputOGG:
+ m_SoundFormat.m_IsSigned = true;
+ m_SoundFormat.m_SampleBits = 16;
+ break;
+ case outputRAW:
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ default:
+ break;
+ }
+}
+
diff --git a/kradio3/plugins/recording/recording-config.h b/kradio3/plugins/recording/recording-config.h
new file mode 100644
index 0000000..bccbb93
--- /dev/null
+++ b/kradio3/plugins/recording/recording-config.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ recording-config.h - description
+ -------------------
+ begin : Mi Apr 30 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_CONFIG_H
+#define KRADIO_RECORDING_CONFIG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/soundformat.h"
+
+class KConfig;
+struct SF_INFO;
+
+class RecordingConfig
+{
+public:
+ enum OutputFormat {
+ outputWAV,
+ outputAIFF,
+ outputAU,
+ outputMP3,
+ outputOGG,
+ outputRAW
+ };
+
+public:
+ RecordingConfig ();
+ RecordingConfig (const QString &directory,
+ OutputFormat of,
+ const SoundFormat &, int mp3_q, float ogg_q);
+ RecordingConfig (const RecordingConfig &c);
+
+ void restoreConfig(KConfig *c);
+ void saveConfig(KConfig *c) const;
+
+ void getSoundFileInfo(SF_INFO &info, bool input);
+
+ void checkFormatSettings();
+
+public:
+ size_t m_EncodeBufferSize;
+ size_t m_EncodeBufferCount;
+
+ SoundFormat m_SoundFormat;
+ int m_mp3Quality;
+ float m_oggQuality;
+ QString m_Directory;
+ OutputFormat m_OutputFormat;
+
+ bool m_PreRecordingEnable;
+ int m_PreRecordingSeconds;
+};
+
+
+
+
+#endif
diff --git a/kradio3/plugins/recording/recording-configuration-ui.ui b/kradio3/plugins/recording/recording-configuration-ui.ui
new file mode 100644
index 0000000..a80fece
--- /dev/null
+++ b/kradio3/plugins/recording/recording-configuration-ui.ui
@@ -0,0 +1,731 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>RecordingConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>RecordingConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>468</width>
+ <height>197</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>RecordingConfigurationUI</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>kTabWidget13</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage_2</cstring>
+ </property>
+ <attribute name="title">
+ <string>Output</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout3_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>editOggQuality</cstring>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>7</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="2">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>editMP3Quality</cstring>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>5</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>labelMP3Quality</cstring>
+ </property>
+ <property name="text">
+ <string>MP3 Quality(0 - high, 9 - low)</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="3" column="2">
+ <property name="name">
+ <cstring>editDirectory</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="2">
+ <item>
+ <property name="text">
+ <string>raw pcm output (.raw)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Microsoft Wave (.wav)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Apple/SGI (.aiff)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Sun/NeXT (.au)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>MP3 Compressed (.mp3)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ogg/Vorbis Compressed (.ogg)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editFileFormat</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>lableDirectory</cstring>
+ </property>
+ <property name="text">
+ <string>Recording Directory</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>lableFileFormat</cstring>
+ </property>
+ <property name="text">
+ <string>File Format</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>labelOggQuality</cstring>
+ </property>
+ <property name="text">
+ <string>Ogg Quality(0 - low, 9 - high)</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer132</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>I&amp;nput</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout69</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>225</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>48000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>44100</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>22050</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>11025</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editRate</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lableEndianess</cstring>
+ </property>
+ <property name="text">
+ <string>Endianess</string>
+ </property>
+ </widget>
+ <spacer row="3" column="2">
+ <property name="name">
+ <cstring>spacer1_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>225</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>Stereo</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mono</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editChannels</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelRate</cstring>
+ </property>
+ <property name="text">
+ <string>Sample Rate</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Little Endian</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Big Endian</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editEndianess</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>16</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>8</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editBits</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>lableChannels</cstring>
+ </property>
+ <property name="text">
+ <string>Channels</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lableBits</cstring>
+ </property>
+ <property name="text">
+ <string>Sample Bits</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="2">
+ <item>
+ <property name="text">
+ <string>Signed</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Unsigned</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editSign</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>225</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer131</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage_3</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Buffers</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>editBufferSize</cstring>
+ </property>
+ <property name="suffix">
+ <string> kB</string>
+ </property>
+ <property name="maxValue">
+ <number>2048</number>
+ </property>
+ <property name="minValue">
+ <number>64</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="value">
+ <number>256</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelEditBufferSize</cstring>
+ </property>
+ <property name="text">
+ <string>Encoding Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>editBufferCount</cstring>
+ </property>
+ <property name="minValue">
+ <number>3</number>
+ </property>
+ <property name="value">
+ <number>3</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>labelEditBufferCount</cstring>
+ </property>
+ <property name="text">
+ <string>Number of Buffers</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer132_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage_4</cstring>
+ </property>
+ <attribute name="title">
+ <string>Pre-Recordin&amp;g</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout68</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_checkboxPreRecordingEnable</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;nable</string>
+ </property>
+ <property name="accel">
+ <string>Alt+N</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>380</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_labelPreRecordingTime</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>PreRecording Time</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>m_spinboxPreRecordingSeconds</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="suffix">
+ <string> s</string>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer132_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>m_checkboxPreRecordingEnable</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_spinboxPreRecordingSeconds</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_checkboxPreRecordingEnable</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_labelPreRecordingTime</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/recording/recording-configuration.cpp b/kradio3/plugins/recording/recording-configuration.cpp
new file mode 100644
index 0000000..d41bf01
--- /dev/null
+++ b/kradio3/plugins/recording/recording-configuration.cpp
@@ -0,0 +1,414 @@
+/***************************************************************************
+ recording-configuration.cpp - description
+ -------------------
+ begin : So Aug 31 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 "recording-configuration.h"
+//#include "recording-context.h"
+
+#include <kurlrequester.h>
+#include <kcombobox.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+
+#include <ktabwidget.h>
+
+
+RecordingConfiguration::RecordingConfiguration (QWidget *parent)
+ : RecordingConfigurationUI(parent),
+ m_dirty(true),
+ m_ignore_gui_updates(false)
+{
+ editDirectory->setMode(KFile::Directory | KFile::ExistingOnly);
+
+ QObject::connect(editFileFormat, SIGNAL(activated(int)),
+ this, SLOT(slotFormatSelectionChanged()));
+ QObject::connect(editBits, SIGNAL(activated(int)),
+ this, SLOT(slotFormatSelectionChanged()));
+
+ connect(editRate, SIGNAL(activated(int)), SLOT(slotSetDirty()));
+ connect(editBits, SIGNAL(activated(int)), SLOT(slotSetDirty()));
+ connect(editSign, SIGNAL(activated(int)), SLOT(slotSetDirty()));
+ connect(editEndianess, SIGNAL(activated(int)), SLOT(slotSetDirty()));
+ connect(editChannels, SIGNAL(activated(int)), SLOT(slotSetDirty()));
+ connect(editFileFormat, SIGNAL(activated(int)), SLOT(slotSetDirty()));
+ connect(editMP3Quality, SIGNAL(valueChanged(int)), SLOT(slotSetDirty()));
+ connect(editOggQuality, SIGNAL(valueChanged(int)), SLOT(slotSetDirty()));
+ connect(editDirectory, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty()));
+ connect(editBufferSize, SIGNAL(valueChanged(int)), SLOT(slotSetDirty()));
+ connect(editBufferCount, SIGNAL(valueChanged(int)), SLOT(slotSetDirty()));
+ connect(m_spinboxPreRecordingSeconds, SIGNAL(valueChanged(int)), SLOT(slotSetDirty()));
+ connect(m_checkboxPreRecordingEnable, SIGNAL(toggled(bool)), SLOT(slotSetDirty()));
+
+// attention: remove items with higher index first ;-) otherwise indexes are not valid
+#ifndef HAVE_OGG
+ editFileFormat->removeItem(FORMAT_OGG_IDX_ORG);
+ delete editOggQuality;
+ editOggQuality = NULL;
+ delete labelOggQuality;
+ labelOggQuality = NULL;
+#endif
+#ifndef HAVE_LAME
+ editFileFormat->removeItem(FORMAT_MP3_IDX_ORG);
+ delete editMP3Quality;
+ editMP3Quality = NULL;
+ delete labelMP3Quality;
+ labelMP3Quality = NULL;
+#endif
+}
+
+
+RecordingConfiguration::~RecordingConfiguration ()
+{
+}
+
+
+void RecordingConfiguration::setGUIBuffers(const RecordingConfig &c)
+{
+ editBufferSize->setValue(c.m_EncodeBufferSize / 1024);
+ editBufferCount->setValue(c.m_EncodeBufferCount);
+}
+
+void RecordingConfiguration::setGUIDirectories(const RecordingConfig &c)
+{
+ editDirectory->setURL(c.m_Directory);
+}
+
+void RecordingConfiguration::setGUISoundFormat(const RecordingConfig &c)
+{
+ switch (c.m_SoundFormat.m_SampleBits) {
+ case 8 : editBits->setCurrentItem(BITS_8_IDX ); break;
+ case 16: editBits->setCurrentItem(BITS_16_IDX); break;
+ default: editBits->setCurrentItem(BITS_16_IDX);
+ }
+ switch (c.m_SoundFormat.m_Channels) {
+ case 1 : editChannels->setCurrentItem(CHANNELS_MONO_IDX); break;
+ case 2 : editChannels->setCurrentItem(CHANNELS_STEREO_IDX); break;
+ default: editChannels->setCurrentItem(CHANNELS_STEREO_IDX); break;
+ }
+ switch (c.m_SoundFormat.m_IsSigned) {
+ case 0 : editSign->setCurrentItem(SIGN_UNSIGNED_IDX); break;
+ case 1 : editSign->setCurrentItem(SIGN_SIGNED_IDX); break;
+ default: editSign->setCurrentItem(SIGN_SIGNED_IDX); break;
+ }
+ switch (c.m_SoundFormat.m_SampleRate) {
+ case 48000: editRate->setCurrentItem(RATE_48000_IDX); break;
+ case 44100: editRate->setCurrentItem(RATE_44100_IDX); break;
+ case 22050: editRate->setCurrentItem(RATE_22050_IDX); break;
+ case 11025: editRate->setCurrentItem(RATE_11025_IDX); break;
+ default: editRate->setCurrentItem(RATE_44100_IDX); break;
+ }
+ switch (c.m_SoundFormat.m_Endianess) {
+ case BIG_ENDIAN : editEndianess->setCurrentItem(ENDIAN_BIG_IDX); break;
+ case LITTLE_ENDIAN : editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX); break;
+ default: editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX); break;
+ }
+}
+
+void RecordingConfiguration::setGUIOutputFormat(const RecordingConfig &c)
+{
+ switch (c.m_OutputFormat) {
+ case RecordingConfig::outputWAV: editFileFormat->setCurrentItem(FORMAT_WAV_IDX); break;
+ case RecordingConfig::outputAIFF: editFileFormat->setCurrentItem(FORMAT_AIFF_IDX); break;
+ case RecordingConfig::outputAU: editFileFormat->setCurrentItem(FORMAT_AU_IDX); break;
+ case RecordingConfig::outputRAW: editFileFormat->setCurrentItem(FORMAT_RAW_IDX); break;
+#ifdef HAVE_LAME
+ case RecordingConfig::outputMP3: editFileFormat->setCurrentItem(FORMAT_MP3_IDX); break;
+#endif
+#ifdef HAVE_OGG
+ case RecordingConfig::outputOGG: editFileFormat->setCurrentItem(FORMAT_OGG_IDX); break;
+#endif
+ default: editFileFormat->setCurrentItem(FORMAT_WAV_IDX); break;
+ }
+}
+
+void RecordingConfiguration::setGUIEncoderQuality(const RecordingConfig &c)
+{
+#ifdef HAVE_LAME
+ editMP3Quality->setValue(c.m_mp3Quality);
+#endif
+#ifdef HAVE_OGG
+ editOggQuality->setValue((int)(c.m_oggQuality * 9));
+#endif
+}
+
+
+void RecordingConfiguration::setGUIPreRecording(const RecordingConfig &c)
+{
+ m_spinboxPreRecordingSeconds->setValue(c.m_PreRecordingSeconds);
+ m_checkboxPreRecordingEnable->setChecked(c.m_PreRecordingEnable);
+}
+
+
+void RecordingConfiguration::slotOK()
+{
+ if (m_dirty) {
+ storeConfig();
+ sendRecordingConfig(m_RecordingConfig);
+ m_dirty = false;
+ }
+}
+
+
+void RecordingConfiguration::storeConfig()
+{
+ RecordingConfig &c = m_RecordingConfig;
+
+ c.m_EncodeBufferSize = editBufferSize->value() * 1024;
+ c.m_EncodeBufferCount = editBufferCount->value();
+
+ c.m_Directory = editDirectory->url();
+
+ switch(editRate->currentItem()) {
+ case RATE_48000_IDX: c.m_SoundFormat.m_SampleRate = 48000; break;
+ case RATE_44100_IDX: c.m_SoundFormat.m_SampleRate = 44100; break;
+ case RATE_22050_IDX: c.m_SoundFormat.m_SampleRate = 22050; break;
+ case RATE_11025_IDX: c.m_SoundFormat.m_SampleRate = 11025; break;
+ default: c.m_SoundFormat.m_SampleRate = 44100; break;
+ }
+ switch(editChannels->currentItem()) {
+ case CHANNELS_MONO_IDX: c.m_SoundFormat.m_Channels = 1; break;
+ case CHANNELS_STEREO_IDX: c.m_SoundFormat.m_Channels = 2; break;
+ default: c.m_SoundFormat.m_Channels = 2; break;
+ }
+ switch(editSign->currentItem()) {
+ case SIGN_UNSIGNED_IDX: c.m_SoundFormat.m_IsSigned = false; break;
+ case SIGN_SIGNED_IDX: c.m_SoundFormat.m_IsSigned = true; break;
+ default: c.m_SoundFormat.m_IsSigned = true; break;
+ }
+ switch(editEndianess->currentItem()) {
+ case ENDIAN_LITTLE_IDX: c.m_SoundFormat.m_Endianess = LITTLE_ENDIAN; break;
+ case ENDIAN_BIG_IDX: c.m_SoundFormat.m_Endianess = BIG_ENDIAN; break;
+ default: c.m_SoundFormat.m_Endianess = LITTLE_ENDIAN; break;
+ }
+ switch(editBits->currentItem()) {
+ case BITS_8_IDX: c.m_SoundFormat.m_SampleBits = 8; break;
+ case BITS_16_IDX: c.m_SoundFormat.m_SampleBits = 16; break;
+ default: c.m_SoundFormat.m_SampleBits = 16; break;
+ }
+ switch(editFileFormat->currentItem()) {
+ case FORMAT_WAV_IDX: c.m_OutputFormat = RecordingConfig::outputWAV; break;
+ case FORMAT_AIFF_IDX: c.m_OutputFormat = RecordingConfig::outputAIFF; break;
+ case FORMAT_AU_IDX: c.m_OutputFormat = RecordingConfig::outputAU; break;
+ case FORMAT_RAW_IDX: c.m_OutputFormat = RecordingConfig::outputRAW; break;
+#ifdef HAVE_LAME
+ case FORMAT_MP3_IDX: c.m_OutputFormat = RecordingConfig::outputMP3; break;
+#endif
+#ifdef HAVE_OGG
+ case FORMAT_OGG_IDX: c.m_OutputFormat = RecordingConfig::outputOGG; break;
+#endif
+ default: c.m_OutputFormat = RecordingConfig::outputWAV; break;
+ }
+#ifdef HAVE_LAME
+ c.m_mp3Quality = editMP3Quality->value();
+#endif
+#ifdef HAVE_OGG
+ c.m_oggQuality = ((float)editOggQuality->value()) / 9.0f;
+#endif
+
+ c.m_PreRecordingEnable = m_checkboxPreRecordingEnable->isChecked();
+ c.m_PreRecordingSeconds = m_spinboxPreRecordingSeconds->value();
+
+ c.checkFormatSettings();
+}
+
+
+void RecordingConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ noticeRecordingConfigChanged(m_RecordingConfig);
+ m_dirty = false;
+ }
+}
+
+
+void RecordingConfiguration::slotFormatSelectionChanged()
+{
+ int bitsIDX = editBits->currentItem();
+ int formatIDX = editFileFormat->currentItem();
+
+ int endianTest = 0x04030201;
+ bool littleEndian = ((char*)&endianTest)[0] == 0x01;
+
+#ifdef HAVE_LAME
+ editMP3Quality ->setEnabled(false);
+ labelMP3Quality->setEnabled(false);
+#endif
+#ifdef HAVE_OGG
+ editOggQuality ->setEnabled(false);
+ labelOggQuality->setEnabled(false);
+#endif
+
+ editBits->setEnabled(true);
+
+ if (formatIDX == FORMAT_MP3_IDX) {
+ editBits->setDisabled(true);
+ editBits->setCurrentItem(BITS_16_IDX);
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(SIGN_SIGNED_IDX);
+#ifdef HAVE_LAME
+ editMP3Quality ->setEnabled(true);
+ labelMP3Quality->setEnabled(true);
+#endif
+ } else if (formatIDX == FORMAT_OGG_IDX) {
+ editBits->setDisabled(true);
+ editBits->setCurrentItem(BITS_16_IDX);
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(SIGN_SIGNED_IDX);
+#ifdef HAVE_OGG
+ editOggQuality ->setEnabled(true);
+ labelOggQuality->setEnabled(true);
+#endif
+ } else {
+ if (bitsIDX == BITS_8_IDX) {
+ if (formatIDX == FORMAT_RAW_IDX || formatIDX == FORMAT_AIFF_IDX) {
+ editSign->setDisabled(false);
+ } else {
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(formatIDX == FORMAT_WAV_IDX ? SIGN_UNSIGNED_IDX : SIGN_SIGNED_IDX);
+ }
+ } else {
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(SIGN_SIGNED_IDX);
+ }
+ }
+
+ switch (formatIDX) {
+ case FORMAT_RAW_IDX :
+ editEndianess->setDisabled(false);
+ break;
+#ifdef HAVE_LAME
+ case FORMAT_MP3_IDX :
+ editEndianess->setCurrentItem(littleEndian ? ENDIAN_LITTLE_IDX : ENDIAN_BIG_IDX);
+ editEndianess->setDisabled(true);
+ break;
+#endif
+#ifdef HAVE_OGG
+ case FORMAT_OGG_IDX :
+ editEndianess->setCurrentItem(littleEndian ? ENDIAN_LITTLE_IDX : ENDIAN_BIG_IDX);
+ editEndianess->setDisabled(true);
+ break;
+#endif
+ default:
+ editEndianess->setDisabled(true);
+ if (formatIDX == FORMAT_AIFF_IDX || formatIDX == FORMAT_AU_IDX) {
+ editEndianess->setCurrentItem(ENDIAN_BIG_IDX);
+ } else {
+ editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX);
+ }
+ break;
+ }
+}
+
+
+
+bool RecordingConfiguration::noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_EncodeBufferSize = BufferSize;
+ m_RecordingConfig.m_EncodeBufferCount = BufferCount;
+ setGUIBuffers(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+
+bool RecordingConfiguration::noticeSoundFormatChanged (const SoundFormat &sf)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_SoundFormat = sf;
+ setGUISoundFormat(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+
+bool RecordingConfiguration::noticeMP3QualityChanged (int q)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_mp3Quality = q;
+ setGUIEncoderQuality(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeOggQualityChanged (float q)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_oggQuality = q;
+ setGUIEncoderQuality(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeRecordingDirectoryChanged(const QString &dir)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_Directory = dir;
+ setGUIDirectories(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeOutputFormatChanged (RecordingConfig::OutputFormat of)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_OutputFormat = of;
+ setGUIOutputFormat(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticePreRecordingChanged (bool enable, int seconds)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_PreRecordingEnable = enable;
+ m_RecordingConfig.m_PreRecordingSeconds = seconds;
+ setGUIPreRecording(m_RecordingConfig);
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeRecordingConfigChanged(const RecordingConfig &c)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig = c;
+ setGUIBuffers(c);
+ setGUIDirectories(c);
+ setGUISoundFormat(c);
+ setGUIOutputFormat(c);
+ setGUIEncoderQuality(c);
+ setGUIPreRecording(c);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+void RecordingConfiguration::slotSetDirty()
+{
+ if (!m_ignore_gui_updates) {
+ m_dirty = true;
+ }
+}
+
+
+#include "recording-configuration.moc"
diff --git a/kradio3/plugins/recording/recording-configuration.h b/kradio3/plugins/recording/recording-configuration.h
new file mode 100644
index 0000000..bf1b8f6
--- /dev/null
+++ b/kradio3/plugins/recording/recording-configuration.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ recording-configuration.h - description
+ -------------------
+ begin : So Aug 31 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_CONFIGURATION_H
+#define KRADIO_RECORDING_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/soundformat.h"
+
+#include "recording-config.h"
+#include "reccfg_interfaces.h"
+#include "recording-configuration-ui.h"
+
+#define RATE_48000_IDX 0
+#define RATE_44100_IDX 1
+#define RATE_22050_IDX 2
+#define RATE_11025_IDX 3
+
+#define CHANNELS_STEREO_IDX 0
+#define CHANNELS_MONO_IDX 1
+
+#define SIGN_SIGNED_IDX 0
+#define SIGN_UNSIGNED_IDX 1
+
+#define BITS_16_IDX 0
+#define BITS_8_IDX 1
+
+#define ENDIAN_LITTLE_IDX 0
+#define ENDIAN_BIG_IDX 1
+
+#define FORMAT_RAW_IDX 0
+#define FORMAT_WAV_IDX 1
+#define FORMAT_AIFF_IDX 2
+#define FORMAT_AU_IDX 3
+#define NEXT_IDX1 4
+
+#define FORMAT_MP3_IDX_ORG 4
+#define FORMAT_OGG_IDX_ORG 5
+
+
+#ifdef HAVE_LAME
+ #define FORMAT_MP3_IDX NEXT_IDX1
+ #define NEXT_IDX2 (NEXT_IDX1+1)
+#else
+ #define FORMAT_MP3_IDX (-1)
+ #define NEXT_IDX2 NEXT_IDX1
+#endif
+
+#ifdef HAVE_OGG
+ #define FORMAT_OGG_IDX NEXT_IDX2
+ #define NEXT_IDX3 (NEXT_IDX2+1)
+#else
+ #define FORMAT_OGG_IDX (-1)
+ #define NEXT_IDX3 NEXT_IDX2
+#endif
+
+
+
+
+
+
+class RecordingConfiguration : public RecordingConfigurationUI,
+ public IRecCfgClient
+{
+Q_OBJECT
+public :
+ RecordingConfiguration (QWidget *parent);
+ ~RecordingConfiguration ();
+
+// IRecCfgClient
+
+ bool noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount);
+ bool noticeSoundFormatChanged (const SoundFormat &sf);
+ bool noticeMP3QualityChanged (int q);
+ bool noticeOggQualityChanged (float q);
+ bool noticeRecordingDirectoryChanged(const QString &dir);
+ bool noticeOutputFormatChanged (RecordingConfig::OutputFormat of);
+ bool noticePreRecordingChanged (bool enable, int seconds);
+ bool noticeRecordingConfigChanged (const RecordingConfig &cfg);
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+ void slotFormatSelectionChanged();
+
+protected:
+
+ void storeConfig();
+
+ void setGUIBuffers(const RecordingConfig &c);
+ void setGUIDirectories(const RecordingConfig &c);
+ void setGUISoundFormat(const RecordingConfig &c);
+ void setGUIOutputFormat(const RecordingConfig &c);
+ void setGUIPreRecording(const RecordingConfig &c);
+ void setGUIEncoderQuality(const RecordingConfig &c);
+
+ RecordingConfig m_RecordingConfig;
+
+ bool m_dirty;
+ bool m_ignore_gui_updates;
+};
+
+
+
+
+#endif
diff --git a/kradio3/plugins/recording/recording-datamonitor.cpp b/kradio3/plugins/recording/recording-datamonitor.cpp
new file mode 100644
index 0000000..cd8e0f5
--- /dev/null
+++ b/kradio3/plugins/recording/recording-datamonitor.cpp
@@ -0,0 +1,278 @@
+/***************************************************************************
+ recording-monitor-widget.cpp - description
+ -------------------
+ begin : So Sep 7 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 "recording-datamonitor.h"
+//#include "recording-context.h"
+#include <math.h>
+
+#include <qpainter.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <kimageeffect.h> // fading, blending, ...
+#include <kpixmapio.h> // fast conversion between QPixmap/QImage
+#include <limits.h>
+#include <stdlib.h>
+
+#include <klocale.h>
+
+#define CHANNEL_H_MIN 20
+#define BLOCK_W_MIN 10
+#define W_MIN (20 * (BLOCK_W_MIN))
+
+RecordingDataMonitor::RecordingDataMonitor(QWidget *parent, const char *name)
+ : QFrame(parent, name),
+ m_channelsMax(NULL),
+ m_channelsAvg(NULL),
+ m_maxValue(INT_MAX),
+ m_channels(0),
+ m_pActiveBlocks(NULL)
+{
+ setFrameStyle(Box | Sunken);
+ setLineWidth(1);
+ setMidLineWidth(1);
+
+ setChannels(2);
+
+ setColors(QColor(20, 244, 20),
+ QColor(10, 117, 10));
+
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+}
+
+
+RecordingDataMonitor::~RecordingDataMonitor()
+{
+ if (m_channelsMax) delete[] m_channelsMax;
+ if (m_channelsAvg) delete[] m_channelsAvg;
+ if (m_pActiveBlocks) delete[] m_pActiveBlocks;
+}
+
+
+
+// own stuff
+
+void RecordingDataMonitor::setChannels(int n)
+{
+ if (n != m_channels) {
+ if (m_channelsMax) delete[] m_channelsMax;
+ if (m_channelsAvg) delete[] m_channelsAvg;
+ if (m_pActiveBlocks) delete[] m_pActiveBlocks;
+ m_channels = n > 0 ? n : 0;
+ if (m_channels > 0) {
+ m_channelsMax = new int[m_channels];
+ m_channelsAvg = new double[m_channels];
+ m_pActiveBlocks = new int[m_channels];
+ for (int i = 0; i < m_channels; ++i) {
+ m_pActiveBlocks[i] = 0;
+ }
+ } else {
+ m_channelsMax = NULL;
+ m_channelsAvg = NULL;
+ m_pActiveBlocks = NULL;
+ }
+ }
+
+ for (int i = 0; i < m_channels; ++i) {
+ m_channelsMax[i] = 0;
+ m_channelsAvg[i] = 0;
+ }
+ setMinimumSize(QSize(W_MIN, (m_channels + 1 )* CHANNEL_H_MIN));
+}
+
+
+// QT/KDE ...
+
+void RecordingDataMonitor::drawContents(QPainter *painter)
+{
+ if (painter)
+ internalDrawContents(*painter, true);
+}
+
+void RecordingDataMonitor::internalDrawContents(QPainter &painter, bool repaintAll)
+{
+ if (m_channels <= 0) return;
+ QRect r = contentsRect();
+
+ QPen activePen (colorGroup().color(QColorGroup::Text), 1);
+ QPen inactivePen (colorGroup().color(QColorGroup::Mid), 1);
+ QBrush activeBrush = colorGroup().brush(QColorGroup::Text);
+ QBrush inactiveBrush = colorGroup().brush(QColorGroup::Mid);
+ QBrush yellowBrush(QColor(255,255,0));
+ QBrush orangeBrush(QColor(255,192,0));
+ QBrush redBrush (QColor(255,0, 0));
+
+
+ double ranges [5] = { 0.75, 0.83, 0.91, 1.0, 999 };
+ QBrush *brushes[5] = { &activeBrush, &yellowBrush, &orangeBrush, &redBrush, &redBrush };
+
+ painter.setBrush( isEnabled() ? activeBrush : inactiveBrush);
+
+ int nBlocks = (r.width()-1) / BLOCK_W_MIN;
+ int xoffs = (r.width()-1) % BLOCK_W_MIN;
+ int chHeight = (r.height()-1-CHANNEL_H_MIN) / m_channels;
+ int yoffs = (r.height()-1) % m_channels;
+
+ double min_dB = 20*log10(1 / (double)m_maxValue );
+
+ int x0 = xoffs/2 + r.top();
+ int y = yoffs/2 + r.left();
+ for (int c = 0; c < m_channels; ++c) {
+ int x = x0;
+
+
+ int startBlock = 0;
+ int endBlock = nBlocks - 1;
+ int oldActiveBlocks = m_pActiveBlocks[c];
+
+ double dBMax = isEnabled() ? 20*log10(m_channelsMax[c] / (double)m_maxValue ) : min_dB;
+
+ m_pActiveBlocks[c] = m_channelsMax[c] ? (int)rint(nBlocks * (min_dB - dBMax) / min_dB) : 0;
+
+ if (!repaintAll) {
+ if (oldActiveBlocks > m_pActiveBlocks[c]) {
+ startBlock = m_pActiveBlocks[c];
+ endBlock = oldActiveBlocks - 1;
+ } else {
+ startBlock = oldActiveBlocks;
+ endBlock = m_pActiveBlocks[c]-1;
+ }
+ }
+
+ int range = 0;
+
+ x += BLOCK_W_MIN * startBlock;
+ for (int b = startBlock; b <= endBlock; ++b) {
+ while (b >= nBlocks * ranges[range]) ++range;
+ painter.fillRect(x+1, y+1, BLOCK_W_MIN-1, chHeight-1,
+ b < m_pActiveBlocks[c] ? *brushes[range] : inactiveBrush);
+ x += BLOCK_W_MIN;
+ }
+
+ y += chHeight;
+ }
+
+ if (repaintAll) {
+ QFont f("Helvetica");
+ painter.setPen (activePen);
+ f.setPixelSize(CHANNEL_H_MIN);
+ painter.setFont(f);
+
+ int maxW = QFontMetrics(f).width(i18n("%1 dB").arg((int)min_dB));
+ int delta_dB = 5;
+ while (abs((long)min_dB) / delta_dB * maxW * 2 > r.width()) delta_dB *= 2;
+
+ for (int dB = 0; dB >= min_dB; dB -= delta_dB) {
+ QString txt = i18n("%1 dB").arg(dB);
+ int w = QFontMetrics(f).width(txt);
+ int x = x0 + (int)(nBlocks * BLOCK_W_MIN * (min_dB - dB) / min_dB) - w;
+ if (x < x0) continue;
+ painter.drawText(x, y + CHANNEL_H_MIN, txt);
+ }
+ }
+}
+
+
+bool RecordingDataMonitor::setColors(const QColor &activeText,
+ const QColor &button)
+{
+ m_colorActiveText = activeText;
+ m_colorButton = button;
+
+ QPalette pl = palette();
+ QColorGroup cg = pl.inactive();
+
+ QBrush fg = cg.brush(QColorGroup::Foreground),
+ btn = cg.brush(QColorGroup::Button),
+ lgt = cg.brush(QColorGroup::Light),
+ drk = cg.brush(QColorGroup::Dark),
+ mid = cg.brush(QColorGroup::Mid),
+ txt = cg.brush(QColorGroup::Text),
+ btx = cg.brush(QColorGroup::BrightText),
+ bas = cg.brush(QColorGroup::Base),
+ bg = cg.brush(QColorGroup::Background);
+
+ fg.setColor (m_colorActiveText);
+ btn.setColor(m_colorButton);
+ lgt.setColor(m_colorButton.light(180));
+ drk.setColor(m_colorButton.light( 50));
+ mid.setColor(m_colorButton.light( 75));
+ txt.setColor(m_colorActiveText);
+ btx.setColor(m_colorActiveText);
+ bas.setColor(m_colorButton);
+ bg.setColor (m_colorButton);
+
+ QColorGroup ncg(fg, btn, lgt, drk, mid, txt, btx, bas, bg);
+ pl.setInactive(ncg);
+ pl.setActive(ncg);
+ setPalette(pl);
+
+ if (parentWidget() && parentWidget()->backgroundPixmap() ){
+ KPixmapIO io;
+ QImage i = io.convertToImage(*parentWidget()->backgroundPixmap());
+ KImageEffect::fade(i, 0.5, colorGroup().color(QColorGroup::Dark));
+ setPaletteBackgroundPixmap(io.convertToPixmap(i));
+ setBackgroundOrigin(WindowOrigin);
+ } else {
+ setBackgroundColor(colorGroup().color(QColorGroup::Button));
+ }
+
+ return true;
+}
+
+
+bool RecordingDataMonitor::noticeSoundStreamData(SoundStreamID /*id*/,
+ const SoundFormat &sf, const char *data, size_t size, size_t &/*consumed_size*/,
+ const SoundMetaData &/*md*/
+)
+{
+ if (!isEnabled())
+ return false;
+ int nSamples = size / sf.frameSize();
+ int sample_size = sf.sampleSize();
+
+ int bias = 0;
+ setChannels(sf.m_Channels);
+ int old_max = m_maxValue;
+ m_maxValue = sf.maxValue();
+ if (!sf.m_IsSigned) {
+ m_maxValue /= 2;
+ bias = -m_maxValue;
+ }
+
+ int c = 0;
+ for (int s = 0; s < nSamples; ++s, ++c, data += sample_size) {
+ if (c >= m_channels) c -= m_channels; // avoid slow c = s % m_channels
+
+ int &m = m_channelsMax[c];
+ int x = abs(sf.convertSampleToInt(data, false) + bias);
+ if (m < x) m = x;
+ m_channelsAvg[c] += x;
+ }
+ for (int i = 0; i < m_channels; ++i)
+ m_channelsAvg[i] /= nSamples;
+
+ QPainter paint(this);
+ if (m_maxValue != old_max) {
+ repaint(true);
+ } else {
+ internalDrawContents(paint, false);
+ }
+ return true;
+}
+
+
+#include "recording-datamonitor.moc"
diff --git a/kradio3/plugins/recording/recording-datamonitor.h b/kradio3/plugins/recording/recording-datamonitor.h
new file mode 100644
index 0000000..c0b7c40
--- /dev/null
+++ b/kradio3/plugins/recording/recording-datamonitor.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ recording-monitor-widget.h - description
+ -------------------
+ begin : So Sep 7 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_DATA_MONITOR
+#define KRADIO_RECORDING_DATA_MONITOR
+
+#include <qframe.h>
+#include <qcolor.h>
+
+//#include <kradio/interfaces/recording-interfaces.h>
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+class RecordingDataMonitor : public QFrame//,
+ //public ISoundStreamClient
+ //public IRecordingClient
+{
+Q_OBJECT
+public:
+ RecordingDataMonitor(QWidget *parent, const char *name);
+ ~RecordingDataMonitor();
+
+ bool noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md);
+
+// QT/KDE ...
+
+protected:
+
+ void drawContents(QPainter *p);
+ void internalDrawContents(QPainter &painter, bool repaintAll);
+// own stuff ...
+
+protected:
+
+ void setChannels(int n);
+ bool setColors(const QColor &activeColor, const QColor &bkgnd);
+
+// data
+protected:
+
+ int *m_channelsMax; // maximum absolute value recorded on each channel
+ double *m_channelsAvg; // average value recorded on each channel
+ int m_maxValue; // maximum absolute value possible for samples
+ int m_channels;
+
+ QColor m_colorActiveText, m_colorButton;
+
+ int *m_pActiveBlocks;
+};
+
+#endif
diff --git a/kradio3/plugins/recording/recording-monitor.cpp b/kradio3/plugins/recording/recording-monitor.cpp
new file mode 100644
index 0000000..5d6dbf9
--- /dev/null
+++ b/kradio3/plugins/recording/recording-monitor.cpp
@@ -0,0 +1,402 @@
+/***************************************************************************
+ recording-monitor.cpp - description
+ -------------------
+ begin : Mo Sep 1 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 "recording-monitor.h"
+#include "recording-datamonitor.h"
+#include "../../src/include/aboutwidget.h"
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <kcombobox.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kaboutdata.h>
+
+RecordingMonitor::RecordingMonitor(const QString &name)
+ : QWidget(NULL, name.ascii()),
+ WidgetPluginBase(name, i18n("Recording Monitor")),
+ m_recording(false),
+ m_defaultStreamDescription(QString::null)
+{
+ setCaption(i18n("KRadio Recording Monitor"));
+
+ QVBoxLayout *l = new QVBoxLayout(this, 10, 4);
+ QGridLayout *l0 = new QGridLayout(l, 6, 2);
+
+ l0->addWidget( new QLabel(i18n("SoundStream"), this), 0, 0);
+ l0->addWidget(m_comboSoundStreamSelector = new KComboBox( this), 0, 1);
+ l0->addWidget( new QLabel(i18n("Status"), this), 1, 0);
+ l0->addWidget(m_labelStatus = new QLabel(i18n("<undefined>"), this), 1, 1);
+ l0->addWidget( new QLabel(i18n("Recording File"), this), 2, 0);
+ l0->addWidget(m_labelFileName = new QLabel(i18n("<undefined>"), this), 2, 1);
+ l0->addWidget( new QLabel(i18n("File Size"), this), 3, 0);
+ l0->addWidget(m_labelSize = new QLabel(i18n("<undefined>"), this), 3, 1);
+ l0->addWidget( new QLabel(i18n("Recording Time"), this), 4, 0);
+ l0->addWidget(m_labelTime = new QLabel(i18n("<undefined>"), this), 4, 1);
+ l0->addWidget( new QLabel(i18n("Sample Rate"), this), 5, 0);
+ l0->addWidget(m_labelRate = new QLabel(i18n("<undefined>"), this), 5, 1);
+
+ QPushButton *close = new QPushButton(i18n("&Close"), this);
+ m_btnStartStop = new QPushButton(i18n("&Record"), this);
+ QObject::connect(close, SIGNAL(clicked()), this, SLOT(hide()));
+ QObject::connect(m_btnStartStop, SIGNAL(clicked()), this, SLOT(slotStartStopRecording()));
+
+ m_dataMonitor = new RecordingDataMonitor(this, NULL);
+ m_dataMonitor->setEnabled(false);
+
+ QHBoxLayout *hl0 = new QHBoxLayout(l);
+ hl0->addWidget(m_dataMonitor);
+
+ QHBoxLayout *hl2 = new QHBoxLayout(l);
+ hl2->addItem(new QSpacerItem(10, 1));
+ hl2->addWidget(close);
+ hl2->addWidget(m_btnStartStop);
+ hl2->addItem(new QSpacerItem(10, 1));
+
+
+ m_comboSoundStreamSelector->insertItem(i18n("nothing"));
+ QObject::connect(m_comboSoundStreamSelector, SIGNAL(activated(int)), this, SLOT(slotStreamSelected(int)));
+
+ updateRecordingButton();
+}
+
+
+RecordingMonitor::~RecordingMonitor()
+{
+}
+
+// WidgetPluginBase
+
+void RecordingMonitor::saveState (KConfig *config) const
+{
+ config->setGroup(QString("recordingmonitor-") + name());
+
+ WidgetPluginBase::saveState(config);
+}
+
+
+void RecordingMonitor::restoreState (KConfig *config)
+{
+ config->setGroup(QString("recordingmonitor-") + name());
+
+ WidgetPluginBase::restoreState(config, false);
+}
+
+
+bool RecordingMonitor::connectI(Interface *i)
+{
+ bool a = ISoundStreamClient::connectI(i);
+ bool b = WidgetPluginBase::connectI(i);
+ return a || b;
+}
+
+bool RecordingMonitor::disconnectI(Interface *i)
+{
+ bool a = ISoundStreamClient::disconnectI(i);
+ bool b = WidgetPluginBase::disconnectI(i);
+ if (a) {
+ m_comboSoundStreamSelector->clear();
+ m_SoundStreamID2idx.clear();
+ m_idx2SoundStreamID.clear();
+ m_comboSoundStreamSelector->insertItem(i18n("nothing"));
+ }
+ return a || b;
+}
+
+
+void RecordingMonitor::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_notifySoundStreamCreated(this);
+ s->register4_notifySoundStreamClosed(this);
+ s->register4_notifySoundStreamChanged(this);
+ s->register4_notifySoundStreamData(this);
+ s->register4_sendStartRecordingWithFormat(this);
+ s->register4_sendStopRecording(this);
+
+ QMap<QString, SoundStreamID> tmp;
+ queryEnumerateSoundStreams(tmp);
+
+ m_comboSoundStreamSelector->clear();
+ m_SoundStreamID2idx.clear();
+ m_idx2SoundStreamID.clear();
+ m_comboSoundStreamSelector->insertItem(i18n("nothing"));
+ QMapConstIterator<QString, SoundStreamID> end = tmp.end();
+ for (QMapConstIterator<QString, SoundStreamID> it = tmp.begin(); it != end; ++it) {
+ int idx = m_comboSoundStreamSelector->count();
+ m_comboSoundStreamSelector->insertItem(it.key());
+ m_idx2SoundStreamID[idx] = *it;
+ m_SoundStreamID2idx[*it] = idx;
+ }
+ }
+}
+
+ConfigPageInfo RecordingMonitor::createConfigurationPage()
+{
+ return ConfigPageInfo();
+}
+
+AboutPageInfo RecordingMonitor::createAboutPage()
+{
+/* KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("Recording Monitor Plugin for KRadio"),
+ KAboutData::License_GPL,
+ "(c) 2002-2005 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/kradio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed),
+ i18n("Recording Monitor"),
+ i18n("Recording Monitor Plugin"),
+ "goto"
+ );
+*/
+ return AboutPageInfo();
+}
+
+
+void RecordingMonitor::show()
+{
+ WidgetPluginBase::pShow();
+ QWidget::show();
+}
+
+
+void RecordingMonitor::showOnOrgDesktop()
+{
+ WidgetPluginBase::pShowOnOrgDesktop();
+ //QWidget::show();
+}
+
+void RecordingMonitor::hide()
+{
+ WidgetPluginBase::pHide();
+ QWidget::hide();
+}
+
+
+void RecordingMonitor::showEvent(QShowEvent *e)
+{
+ QWidget::showEvent(e);
+ WidgetPluginBase::pShowEvent(e);
+ //m_comboSoundStreamSelector->setCurrentItem(1);
+ //slotStreamSelected(1);
+}
+
+
+void RecordingMonitor::hideEvent(QHideEvent *e)
+{
+ QWidget::hideEvent(e);
+ WidgetPluginBase::pHideEvent(e);
+ m_comboSoundStreamSelector->setCurrentItem(0);
+ slotStreamSelected(0);
+}
+
+
+void RecordingMonitor::slotStartStopRecording()
+{
+ if (m_currentStream.isValid()) {
+ if (m_recording) {
+ sendStopRecording(m_currentStream);
+ } else {
+ sendStartRecording(m_currentStream);
+ }
+ }
+ updateRecordingButton();
+}
+
+
+bool RecordingMonitor::noticeSoundStreamCreated(SoundStreamID id)
+{
+ QString tmp = QString::null;
+ querySoundStreamDescription(id, tmp);
+
+ int idx = m_comboSoundStreamSelector->count();
+ m_comboSoundStreamSelector->insertItem(tmp);
+ m_idx2SoundStreamID[idx] = id;
+ m_SoundStreamID2idx[id] = idx;
+
+ if (tmp == m_defaultStreamDescription) {
+ m_comboSoundStreamSelector->setCurrentItem(idx);
+ slotStreamSelected(idx);
+ }
+ return true;
+}
+
+
+bool RecordingMonitor::noticeSoundStreamClosed(SoundStreamID id)
+{
+ if (m_SoundStreamID2idx.contains(id)) {
+ int idx = m_SoundStreamID2idx[id];
+ m_idx2SoundStreamID.clear();
+ m_SoundStreamID2idx.remove(id);
+ QMapIterator<SoundStreamID, int> end = m_SoundStreamID2idx.end();
+ for (QMapIterator<SoundStreamID, int> it = m_SoundStreamID2idx.begin(); it != end; ++it) {
+ if (*it > idx) {
+ (*it)--;
+ }
+ m_idx2SoundStreamID[*it] = it.key();
+ }
+ m_comboSoundStreamSelector->removeItem(idx);
+ slotStreamSelected(m_comboSoundStreamSelector->currentItem());
+ return true;
+ }
+ return false;
+}
+
+
+bool RecordingMonitor::noticeSoundStreamChanged(SoundStreamID id)
+{
+ if (m_SoundStreamID2idx.contains(id)) {
+ int idx = m_SoundStreamID2idx[id];
+ QString tmp = QString::null;
+ querySoundStreamDescription(id, tmp);
+ m_comboSoundStreamSelector->changeItem(tmp, idx);
+ if (idx == m_comboSoundStreamSelector->currentItem()) {
+ m_defaultStreamDescription = tmp;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool RecordingMonitor::startRecordingWithFormat(SoundStreamID id, const SoundFormat &/*sf*/, SoundFormat &/*real_format*/)
+{
+ if (id == m_currentStream) {
+ m_recording = true;
+ updateRecordingButton();
+ }
+ return false;
+}
+
+bool RecordingMonitor::stopRecording(SoundStreamID id)
+{
+ if (id == m_currentStream) {
+ m_recording = false;
+ updateRecordingButton();
+ }
+ return false;
+}
+
+bool RecordingMonitor::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+)
+{
+ if (m_idx2SoundStreamID[m_comboSoundStreamSelector->currentItem()] == id) {
+
+ m_labelFileName->setText(md.url().url());
+
+ double B = (double)md.position() + (double)size;
+
+ double s = md.relativeTimestamp();
+
+ int m = (int)(s / 60); s -= 60 * m;
+ int h = m / 60; m %= 60;
+ int d = h / 24; h %= 24;
+ QString time;
+ if (d) {
+ time.sprintf("%dd - %02d:%02d:%05.2f", d, h, m, s);
+ } else {
+ time.sprintf("%02d:%02d:%05.2f", h, m, s);
+ }
+ m_labelTime->setText(time);
+
+ if (sf.m_Encoding == "raw") {
+ m_dataMonitor->setEnabled(true);
+ m_dataMonitor->noticeSoundStreamData(id, sf, data, size, consumed_size, md);
+ } else {
+ m_dataMonitor->setEnabled(false);
+ }
+
+ double kB = B / 1024;
+ double MB = kB / 1024;
+ double GB = MB / 1024;
+ QString str_size;
+ str_size = i18n("%1 Byte").arg(KGlobal::locale()->formatNumber((int)B, 0));
+ if (kB > 1) str_size = i18n("%1 kB").arg(KGlobal::locale()->formatNumber(kB, 3));
+ if (MB > 1) str_size = i18n("%1 MB").arg(KGlobal::locale()->formatNumber(MB, 3));
+ if (GB > 1) str_size = i18n("%1 GB").arg(KGlobal::locale()->formatNumber(GB, 3));
+ m_labelSize->setText(str_size);
+
+ m_labelRate->setText(i18n("%1 Hz").arg(sf.m_SampleRate));
+ return true;
+ }
+ return false;
+}
+
+
+void RecordingMonitor::slotStreamSelected(int idx)
+{
+ SoundStreamID old_id = m_currentStream;
+ if (old_id.isValid()) {
+ sendStopCapture(old_id);
+ }
+
+ SoundStreamID id = m_idx2SoundStreamID.contains(idx) ? m_idx2SoundStreamID[idx] : SoundStreamID::InvalidID;
+ if (id.isValid()) {
+
+ m_defaultStreamDescription = m_comboSoundStreamSelector->text(idx);
+
+ SoundFormat sf;
+ sendStartCaptureWithFormat(id, sf, sf);
+ m_dataMonitor ->setEnabled(true);
+ m_labelSize ->setEnabled(true);
+ m_labelSize ->setEnabled(true);
+ m_labelTime ->setEnabled(true);
+ m_labelRate ->setEnabled(true);
+ m_labelFileName ->setEnabled(true);
+ m_labelStatus ->setEnabled(true);
+ } else {
+ m_dataMonitor ->setEnabled(false);
+ m_labelSize ->setEnabled(false);
+ m_labelSize ->setEnabled(false);
+ m_labelTime ->setEnabled(false);
+ m_labelRate ->setEnabled(false);
+ m_labelFileName ->setEnabled(false);
+ m_labelStatus ->setEnabled(false);
+ }
+ m_currentStream = id;
+ m_recording = false;
+ SoundFormat sf;
+ queryIsRecordingRunning(m_currentStream, m_recording, sf);
+ updateRecordingButton();
+}
+
+
+void RecordingMonitor::updateRecordingButton()
+{
+ if (m_currentStream.isValid()) {
+ m_btnStartStop->setText(!m_recording ? i18n("&Record") : i18n("&Stop Recording"));
+ m_btnStartStop->setEnabled(true);
+ } else {
+ m_btnStartStop->setText(i18n("&Record"));
+ m_btnStartStop->setEnabled(false);
+ }
+}
+
+
+#include "recording-monitor.moc"
diff --git a/kradio3/plugins/recording/recording-monitor.h b/kradio3/plugins/recording/recording-monitor.h
new file mode 100644
index 0000000..c34e927
--- /dev/null
+++ b/kradio3/plugins/recording/recording-monitor.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+ recording-monitor.h - description
+ -------------------
+ begin : Mo Sep 1 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_MONITOR_H
+#define KRADIO_RECORDING_MONITOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+
+#include "../../src/include/widgetplugins.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+//#include <kradio/interfaces/recording-interfaces.h>
+
+
+class QLabel;
+class QPushButton;
+class QCheckBox;
+class RecordingDataMonitor;
+class KComboBox;
+
+class RecordingMonitor : public QWidget,
+ public WidgetPluginBase,
+ public ISoundStreamClient
+ //public IRecordingClient
+{
+Q_OBJECT
+public:
+
+ RecordingMonitor(const QString &name);
+ virtual ~RecordingMonitor();
+
+ const QString &name() const { return PluginBase::name(); }
+ QString &name() { return PluginBase::name(); }
+
+ virtual QString pluginClassName() const { return "RecordingMonitor"; }
+
+ // WidgetPluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // IRecordingClient
+
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool noticeSoundStreamCreated(SoundStreamID id);
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamChanged(SoundStreamID id);
+
+ bool startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format);
+ bool stopRecording(SoundStreamID id);
+
+ bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md);
+
+public slots:
+
+ void toggleShown() { WidgetPluginBase::pToggleShown(); }
+ void showOnOrgDesktop();
+ void show();
+ void hide();
+
+ void slotStartStopRecording();
+
+ void slotStreamSelected(int idx);
+
+protected:
+
+ virtual void updateRecordingButton();
+
+ virtual void showEvent(QShowEvent *);
+ virtual void hideEvent(QHideEvent *);
+
+ const QWidget *getWidget() const { return this; }
+ QWidget *getWidget() { return this; }
+
+
+protected:
+
+ QLabel *m_labelSize;
+ QLabel *m_labelTime;
+ QLabel *m_labelRate;
+ QLabel *m_labelFileName;
+ QLabel *m_labelStatus;
+ QPushButton *m_btnStartStop;
+
+ KComboBox *m_comboSoundStreamSelector;
+ QMap<SoundStreamID, int> m_SoundStreamID2idx;
+ QMap<int, SoundStreamID> m_idx2SoundStreamID;
+
+ SoundStreamID m_currentStream;
+ RecordingDataMonitor *m_dataMonitor;
+
+ bool m_recording;
+ QString m_defaultStreamDescription;
+};
+
+
+
+
+#endif
diff --git a/kradio3/plugins/recording/recording.cpp b/kradio3/plugins/recording/recording.cpp
new file mode 100644
index 0000000..b2222ab
--- /dev/null
+++ b/kradio3/plugins/recording/recording.cpp
@@ -0,0 +1,736 @@
+/***************************************************************************
+ recording.cpp - description
+ -------------------
+ begin : Mi Aug 27 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 "../../src/include/radiostation.h"
+#include "../../src/include/errorlog-interfaces.h"
+#include "../../src/include/aboutwidget.h"
+#include "../../src/include/fileringbuffer.h"
+#include "../../src/include/utils.h"
+
+#include "recording.h"
+#include "recording-configuration.h"
+#include "soundstreamevent.h"
+#include "recording-monitor.h"
+#include "encoder_mp3.h"
+#include "encoder_ogg.h"
+#include "encoder_pcm.h"
+
+#include <qevent.h>
+#include <qapplication.h>
+#include <qregexp.h>
+
+#include <kconfig.h>
+#include <kdeversion.h>
+
+#include <kaboutdata.h>
+
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS2(
+ Recording, "kradio-recording", i18n("KRadio Recording Plugin"),
+ RecordingMonitor, i18n("KRadio Recording Monitor")
+);
+
+///////////////////////////////////////////////////////////////////////
+
+Recording::Recording(const QString &name)
+ : QObject(NULL, NULL),
+ PluginBase(name, i18n("KRadio Recording Plugin")),
+ m_config()
+{
+}
+
+
+Recording::~Recording()
+{
+ QMapIterator<SoundStreamID, RecordingEncoding*> it = m_EncodingThreads.begin();
+ QMapIterator<SoundStreamID, RecordingEncoding*> end = m_EncodingThreads.end();
+ for (; it != end; ++it) {
+ sendStopRecording(it.key());
+ }
+}
+
+
+bool Recording::connectI(Interface *i)
+{
+ bool a = IRecCfg::connectI(i);
+ bool b = PluginBase::connectI(i);
+ bool c = ISoundStreamClient::connectI(i);
+ return a || b || c;
+}
+
+
+bool Recording::disconnectI(Interface *i)
+{
+ bool a = IRecCfg::disconnectI(i);
+ bool b = PluginBase::disconnectI(i);
+ bool c = ISoundStreamClient::disconnectI(i);
+ return a || b || c;
+}
+
+
+void Recording::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_sendStartPlayback(this);
+ s->register4_sendStopPlayback(this);
+ s->register4_sendStartRecording(this);
+ s->register4_sendStartRecordingWithFormat(this);
+ s->register4_notifySoundStreamData(this);
+ s->register4_sendStopRecording(this);
+ s->register4_queryIsRecordingRunning(this);
+ s->register4_querySoundStreamDescription(this);
+ s->register4_querySoundStreamRadioStation(this);
+ s->register4_queryEnumerateSoundStreams(this);
+ s->register4_notifySoundStreamChanged(this);
+ s->register4_notifySoundStreamClosed(this);
+ }
+}
+
+// PluginBase
+
+void Recording::saveState (KConfig *c) const
+{
+ c->setGroup(QString("recording-") + PluginBase::name());
+ m_config.saveConfig(c);
+}
+
+
+void Recording::restoreState (KConfig *c)
+{
+ c->setGroup(QString("recording-") + PluginBase::name());
+ RecordingConfig cfg;
+ cfg.restoreConfig(c);
+ setRecordingConfig(cfg);
+ //notifyRecordingConfigChanged(m_config);
+}
+
+
+ConfigPageInfo Recording::createConfigurationPage()
+{
+ RecordingConfiguration *c = new RecordingConfiguration(NULL);
+ connectI(c);
+ return ConfigPageInfo(c,
+ i18n("Recording"),
+ i18n("Recording"),
+ "kradio_record");
+}
+
+
+AboutPageInfo Recording::createAboutPage()
+{
+/* KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("Recording Monitor for KRadio"),
+ KAboutData::License_GPL,
+ "(c) 2002-2005 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/kradio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed),
+ i18n("Recording"),
+ i18n("Recording Plugin"),
+ "kradio_record"
+ );*/
+ return AboutPageInfo();
+}
+
+
+// IRecCfg
+
+bool Recording::setEncoderBuffer (size_t BufferSize, size_t BufferCount)
+{
+ if (m_config.m_EncodeBufferSize != BufferSize ||
+ m_config.m_EncodeBufferCount != BufferCount)
+ {
+ m_config.m_EncodeBufferSize = BufferSize;
+ m_config.m_EncodeBufferCount = BufferCount;
+ notifyEncoderBufferChanged(BufferSize, BufferCount);
+ }
+ return true;
+}
+
+bool Recording::setSoundFormat (const SoundFormat &sf)
+{
+ if (m_config.m_SoundFormat != sf) {
+ m_config.m_SoundFormat = sf;
+ notifySoundFormatChanged(sf);
+ }
+ return true;
+}
+
+bool Recording::setMP3Quality (int q)
+{
+ if (m_config.m_mp3Quality != q) {
+ m_config.m_mp3Quality = q;
+ notifyMP3QualityChanged(q);
+ }
+ return true;
+}
+
+bool Recording::setOggQuality (float q)
+{
+ if (m_config.m_oggQuality != q) {
+ m_config.m_oggQuality = q;
+ notifyOggQualityChanged(q);
+ }
+ return true;
+}
+
+bool Recording::setRecordingDirectory(const QString &dir)
+{
+ if (m_config.m_Directory != dir) {
+ m_config.m_Directory = dir;
+ notifyRecordingDirectoryChanged(dir);
+ }
+ return true;
+}
+
+bool Recording::setOutputFormat (RecordingConfig::OutputFormat of)
+{
+ if (m_config.m_OutputFormat != of) {
+ m_config.m_OutputFormat = of;
+ notifyOutputFormatChanged(of);
+ }
+ return true;
+}
+
+bool Recording::setPreRecording (bool enable, int seconds)
+{
+ if (m_config.m_PreRecordingEnable != enable || m_config.m_PreRecordingSeconds != seconds) {
+ m_config.m_PreRecordingEnable = enable;
+ m_config.m_PreRecordingSeconds = seconds;
+
+ if (enable) {
+ for (QMapIterator<SoundStreamID,FileRingBuffer*> it = m_PreRecordingBuffers.begin(); it != m_PreRecordingBuffers.end(); ++it) {
+ if (*it != NULL) {
+ delete *it;
+ }
+ *it = new FileRingBuffer(m_config.m_Directory + "/kradio-prerecord-"+QString::number(it.key().getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize());
+ SoundFormat sf = m_config.m_SoundFormat;
+ sendStartCaptureWithFormat(it.key(), sf, sf, false);
+ }
+ }
+ else {
+ for (QMapIterator<SoundStreamID,FileRingBuffer*> it = m_PreRecordingBuffers.begin(); it != m_PreRecordingBuffers.end(); ++it) {
+ if (*it != NULL) {
+ sendStopCapture(it.key());
+ delete *it;
+ }
+ }
+ m_PreRecordingBuffers.clear();
+ }
+
+ notifyPreRecordingChanged(enable, seconds);
+ }
+ return true;
+}
+
+void Recording::getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const
+{
+ BufferSize = m_config.m_EncodeBufferSize;
+ BufferCount = m_config.m_EncodeBufferCount;
+}
+
+const SoundFormat &Recording::getSoundFormat () const
+{
+ return m_config.m_SoundFormat;
+}
+
+int Recording::getMP3Quality () const
+{
+ return m_config.m_mp3Quality;
+}
+
+float Recording::getOggQuality () const
+{
+ return m_config.m_oggQuality;
+}
+
+const QString &Recording::getRecordingDirectory() const
+{
+ return m_config.m_Directory;
+}
+
+RecordingConfig::OutputFormat Recording::getOutputFormat() const
+{
+ return m_config.m_OutputFormat;
+}
+
+bool Recording::getPreRecording(int &seconds) const
+{
+ seconds = m_config.m_PreRecordingSeconds;
+ return m_config.m_PreRecordingEnable;
+}
+
+const RecordingConfig &Recording::getRecordingConfig() const
+{
+ return m_config;
+}
+
+bool Recording::setRecordingConfig(const RecordingConfig &c)
+{
+ setEncoderBuffer (c.m_EncodeBufferSize, c.m_EncodeBufferCount);
+ setSoundFormat (c.m_SoundFormat);
+ setMP3Quality (c.m_mp3Quality);
+ setOggQuality (c.m_oggQuality);
+ setRecordingDirectory(c.m_Directory);
+ setOutputFormat (c.m_OutputFormat);
+ setPreRecording (c.m_PreRecordingEnable, c.m_PreRecordingSeconds);
+
+ m_config = c;
+
+ notifyRecordingConfigChanged(m_config);
+
+ return true;
+}
+
+
+// ISoundStreamClient
+bool Recording::startPlayback(SoundStreamID id)
+{
+ if (m_PreRecordingBuffers.contains(id))
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers[id] = NULL;
+ if (m_config.m_PreRecordingEnable) {
+ m_PreRecordingBuffers[id] = new FileRingBuffer(m_config.m_Directory + "/kradio-prerecord-"+QString::number(id.getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize());
+ SoundFormat sf = m_config.m_SoundFormat;
+ sendStartCaptureWithFormat(id, sf, sf, false);
+ }
+ return false;
+}
+
+bool Recording::stopPlayback(SoundStreamID id)
+{
+ if (m_PreRecordingBuffers.contains(id)) {
+ if (m_PreRecordingBuffers[id])
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers.remove(id);
+ sendStopCapture(id);
+ }
+ return false;
+}
+
+bool Recording::startRecording(SoundStreamID id)
+{
+
+/* FileRingBuffer *test = new FileRingBuffer("/tmp/ringbuffertest", 2048);
+ char buffer1[1024];
+ char buffer2[1024];
+ char buffer3[1024];
+ for (int i = 0; i < 1024; ++i) {
+ buffer1[i] = 'a';
+ buffer2[i] = 'b';
+ buffer3[i] = 'c';
+ }
+ test->addData(buffer1, 1024);
+ test->addData(buffer2, 1024);
+ test->removeData(1024);
+ test->addData(buffer3, 1024);
+*/
+
+ SoundFormat realFormat = m_config.m_SoundFormat;
+ return sendStartRecordingWithFormat(id, realFormat, realFormat);
+}
+
+bool Recording::startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format)
+{
+ if (!sendStartCaptureWithFormat(id, sf, real_format, /* force_format = */ true)) {
+ logError(i18n("start capture not handled"));
+ return false;
+ }
+
+ RecordingConfig cfg = m_config;
+ cfg.m_SoundFormat = real_format;
+
+ logInfo(i18n("Recording starting"));
+ if (!startEncoder(id, cfg)) {
+ logError(i18n("starting encoding thread failed"));
+ sendStopCapture(id);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Recording::stopRecording(SoundStreamID id)
+{
+ if (m_EncodingThreads.contains(id)) {
+ sendStopCapture(id);
+ if (m_config.m_PreRecordingEnable) {
+ if (!m_PreRecordingBuffers.contains(id)) {
+ if (m_PreRecordingBuffers[id] != NULL) {
+ delete m_PreRecordingBuffers[id];
+ }
+ bool b = false;
+ queryIsPlaybackRunning(id, b);
+ if (b) {
+ m_PreRecordingBuffers[id] = new FileRingBuffer(m_config.m_Directory + "/kradio-prerecord-"+QString::number(id.getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize());
+ } else {
+ m_PreRecordingBuffers[id] = NULL;
+ }
+ }
+ }
+ stopEncoder(id);
+ return true;
+ }
+ return false;
+}
+
+
+
+bool Recording::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &/*sf*/, const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+)
+{
+ if (m_PreRecordingBuffers.contains(id) && m_PreRecordingBuffers[id] != NULL) {
+
+ FileRingBuffer &fbuf = *m_PreRecordingBuffers[id];
+ if (fbuf.getFreeSize() < size) {
+ fbuf.removeData(size - fbuf.getFreeSize());
+ }
+ size_t n = fbuf.addData(data, size);
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? n : min(consumed_size, n);
+// if (n != size) {
+// logDebug("recording packet: was not written completely to tmp buf");
+// }
+
+// //BEGIN DEBUG
+// char tmp[4096];
+// for (unsigned int i = 0; i < sizeof(tmp); ++i) { tmp[i] = 0; }
+// if (fbuf.getFreeSize() < sizeof(tmp)) {
+// fbuf.removeData(sizeof(tmp) - fbuf.getFreeSize());
+// }
+// fbuf.addData((char*)tmp, sizeof(tmp));
+// //END DEBUG
+
+ if (m_EncodingThreads.contains(id)) {
+
+ //logDebug("recording packet: " + QString::number(size));
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ //logDebug("noticeSoundStreamData thread = " + QString::number((long long)thread, 16));
+
+ size_t remSize = fbuf.getFillSize();
+
+ while (remSize > 0) {
+ size_t bufferSize = remSize;
+ char *buf = thread->lockInputBuffer(bufferSize);
+ if (!buf) {
+ // Encoder buffer is full and bigger than remaining data
+ break;
+ }
+ if (bufferSize > remSize) {
+ bufferSize = remSize;
+ }
+ if (fbuf.takeData(buf, bufferSize) != bufferSize) {
+ logError(i18n("could not read suffient data"));
+ }
+
+ thread->unlockInputBuffer(bufferSize, md);
+ remSize -= bufferSize;
+ }
+
+ if (remSize == 0) {
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers.remove(id);
+ }
+ }
+
+ return true;
+ }
+
+ else if (m_EncodingThreads.contains(id)) {
+
+ //logDebug("recording packet: " + QString::number(size));
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ //logDebug("noticeSoundStreamData thread = " + QString::number((long long)thread, 16));
+
+ size_t remSize = size;
+ const char *remData = data;
+
+ while (remSize > 0) {
+ size_t bufferSize = remSize;
+ char *buf = thread->lockInputBuffer(bufferSize);
+ if (!buf) {
+ logWarning(i18n("Encoder input buffer overflow (buffer configuration problem?). Skipped %1 input bytes").arg(QString::number(remSize)));
+ break;
+ }
+ if (bufferSize > remSize) {
+ bufferSize = remSize;
+ }
+ memcpy(buf, remData, bufferSize);
+
+ thread->unlockInputBuffer(bufferSize, md);
+ remSize -= bufferSize;
+ remData += bufferSize;
+ }
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? size - remSize : min(consumed_size, size - remSize);
+
+ return true;
+ }
+ return false;
+}
+
+
+
+
+bool Recording::startEncoder(SoundStreamID ssid, const RecordingConfig &cfg)
+{
+ if (m_EncodingThreads.contains(ssid))
+ return false;
+
+ SoundStreamID encID = createNewSoundStream(ssid, false);
+ m_RawStreams2EncodedStreams[ssid] = encID;
+ m_EncodedStreams2RawStreams[encID] = ssid;
+
+ QString ext = ".wav";
+ switch (m_config.m_OutputFormat) {
+ case RecordingConfig::outputWAV: ext = ".wav"; break;
+ case RecordingConfig::outputAIFF: ext = ".aiff"; break;
+ case RecordingConfig::outputAU: ext = ".au"; break;
+#ifdef HAVE_LAME
+ case RecordingConfig::outputMP3: ext = ".mp3"; break;
+#endif
+#ifdef HAVE_LAME
+ case RecordingConfig::outputOGG: ext = ".ogg"; break;
+#endif
+ case RecordingConfig::outputRAW: ext = ".raw"; break;
+ default: ext = ".wav"; break;
+ }
+ const RadioStation *rs = NULL;
+ querySoundStreamRadioStation(ssid, rs);
+ QString station = rs ? rs->name() + "-" : "";
+ station.replace(QRegExp("[/*?]"), "_");
+
+ QDate date = QDate::currentDate();
+ QTime time = QTime::currentTime();
+ QString sdate;
+
+ sdate.sprintf("%d.%d.%d.%d.%d",date.year(),date.month(),date.day(),time.hour(),time.minute());
+
+ QString output = m_config.m_Directory
+ + "/kradio-recording-"
+ + station
+ + sdate
+ + ext;
+
+ logInfo(i18n("Recording::outputFile: ") + output);
+
+ RecordingEncoding *thread = NULL;
+ switch (m_config.m_OutputFormat) {
+#ifdef HAVE_LAME
+ case RecordingConfig::outputMP3:
+ thread = new RecordingEncodingMP3(this, ssid, cfg, rs, output);
+ break;
+#endif
+#ifdef HAVE_OGG
+ case RecordingConfig::outputOGG:
+ thread = new RecordingEncodingOgg(this, ssid, cfg, rs, output);
+ break;
+#endif
+ default:
+ thread = new RecordingEncodingPCM(this, ssid, cfg, rs, output);
+ }
+
+ //m_encodingThread->openOutput(output, rs);
+
+ if (thread->error()) {
+ //m_context.setError();
+ logError(thread->errorString());
+ } else {
+ thread->start();
+ }
+ // store thread even if it has indicated an error
+ m_EncodingThreads[ssid] = thread;
+
+ //logDebug("startEncoder thread = " + QString::number((long long)thread, 16));
+
+ notifySoundStreamCreated(encID);
+ return !thread->error();
+}
+
+
+void Recording::stopEncoder(SoundStreamID id)
+{
+ if (m_EncodingThreads.contains(id)) {
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ thread->setDone();
+
+ //logDebug("stopEncoder thread = " + QString::number((long long)thread, 16));
+ //logDebug("stopEncoder thread error = " + QString::number(thread->error(), 16));
+
+#if (KDE_VERSION_MAJOR >= 3) && (KDE_VERSION_MINOR >= 1)
+ // FIXME: set a timer and do waiting "in background"
+ if (!thread->wait(5000)) {
+ //m_context.setError();
+ logError(i18n("The encoding thread did not finish. It will be killed now."));
+ thread->terminate();
+ thread->wait();
+ } else {
+#else
+ logError(i18n("Waiting for encoding thread to terminate."));
+ thread->wait();
+#endif
+ if (thread->error()) {
+ //m_context.setError();
+ logError(thread->errorString());
+ } else {
+ //Q_UINT64 size = thread->encodedSize();
+ //m_context.setEncodedSize(low, high);
+ //notifyRecordingContextChanged(m_context);
+ }
+ }
+ delete thread;
+ m_EncodingThreads.remove(id);
+ SoundStreamID encID = m_RawStreams2EncodedStreams[id];
+ m_EncodedStreams2RawStreams.remove(encID);
+ m_RawStreams2EncodedStreams.remove(id);
+ sendStopPlayback(encID);
+ closeSoundStream(encID);
+ logInfo(i18n("Recording stopped"));
+ }
+}
+
+
+bool Recording::event(QEvent *_e)
+{
+ if (SoundStreamEvent::isSoundStreamEvent(_e)) {
+ SoundStreamEvent *e = static_cast<SoundStreamEvent*>(_e);
+ SoundStreamID id = e->getSoundStreamID();
+
+ if (m_EncodingThreads.contains(id)) {
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ //logDebug("Recording::event: thread = " + QString::number((long long)thread, 16));
+
+ if (thread->error()) {
+ logError(thread->errorString());
+ //m_context.setError();
+ stopEncoder(id);
+ } else {
+ //Q_UINT64 size = thread->encodedSize();
+ //m_context.setEncodedSize(low, high);
+ //notifyRecordingContextChanged(m_context);
+ if (e->type() == EncodingTerminated) {
+ stopEncoder(id);
+ } else if (e->type() == EncodingStep) {
+ SoundStreamEncodingStepEvent *step = static_cast<SoundStreamEncodingStepEvent*>(e);
+ size_t consumed_size = SIZE_T_DONT_CARE;
+ notifySoundStreamData(m_RawStreams2EncodedStreams[id], thread->config().m_SoundFormat,
+ step->data(), step->size(), consumed_size, step->metaData());
+ if (consumed_size != SIZE_T_DONT_CARE && consumed_size < step->size()) {
+ logError(i18n("Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes").arg(step->size() - consumed_size));
+ }
+ }
+ }
+ }
+ return true;
+ } else {
+ return QObject::event(_e);
+ }
+}
+
+
+bool Recording::getSoundStreamDescription(SoundStreamID id, QString &descr) const
+{
+ if (m_EncodedStreams2RawStreams.contains(id)) {
+ if (querySoundStreamDescription(m_EncodedStreams2RawStreams[id], descr)) {
+ descr = name() + " - " + descr;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Recording::getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const
+{
+ if (m_EncodedStreams2RawStreams.contains(id)) {
+ if (querySoundStreamRadioStation(m_EncodedStreams2RawStreams[id], rs)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Recording::enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const
+{
+ QMapConstIterator<SoundStreamID,SoundStreamID> end = m_RawStreams2EncodedStreams.end();
+ for (QMapConstIterator<SoundStreamID,SoundStreamID> it = m_RawStreams2EncodedStreams.begin(); it != end; ++it) {
+ QString tmp = QString::null;
+ getSoundStreamDescription(*it, tmp);
+ list[tmp] = *it;
+ }
+ return m_RawStreams2EncodedStreams.count() > 0;
+}
+
+
+bool Recording::noticeSoundStreamChanged(SoundStreamID id)
+{
+ if (m_RawStreams2EncodedStreams.contains(id)) {
+ notifySoundStreamChanged(m_RawStreams2EncodedStreams[id]);
+ return true;
+ }
+ return false;
+}
+
+
+bool Recording::isRecordingRunning(SoundStreamID id, bool &b, SoundFormat &sf) const
+{
+ if (m_EncodingThreads.contains(id)) {
+ b = m_EncodingThreads[id]->running();
+ sf = getSoundFormat();
+ return true;
+ }
+ return false;
+}
+
+
+bool Recording::noticeSoundStreamClosed(SoundStreamID id)
+{
+ if (m_PreRecordingBuffers.contains(id)) {
+ if (m_PreRecordingBuffers[id])
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers.remove(id);
+ }
+
+ if (m_EncodingThreads.contains(id)) {
+ sendStopRecording(id);
+ return true;
+ }
+ return false;
+}
+
+
+#include "recording.moc"
diff --git a/kradio3/plugins/recording/recording.h b/kradio3/plugins/recording/recording.h
new file mode 100644
index 0000000..bef3a3a
--- /dev/null
+++ b/kradio3/plugins/recording/recording.h
@@ -0,0 +1,148 @@
+/***************************************************************************
+ recording.h - description
+ -------------------
+ begin : Mi Aug 27 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_H
+#define KRADIO_RECORDING_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qmap.h>
+
+#include "../../src/include/plugins.h"
+#include "../../src/include/timecontrol_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+#include "recording-config.h"
+#include "reccfg_interfaces.h"
+#include "encoder.h"
+
+class RadioStation;
+class StationList;
+class QSocketNotifier;
+class RecordingEncoding;
+class FileRingBuffer;
+
+class Recording : public QObject,
+ public PluginBase,
+ public ISoundStreamClient,
+ public IRecCfg
+{
+Q_OBJECT
+public:
+ Recording(const QString &name);
+ ~Recording();
+
+ virtual QString pluginClassName() const { return "Recording"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+
+ bool isRecording () const;
+
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+protected:
+
+// IRecCfg
+
+ bool setEncoderBuffer (size_t BufferSize, size_t BufferCount);
+ bool setSoundFormat (const SoundFormat &sf);
+ bool setMP3Quality (int q);
+ bool setOggQuality (float q);
+ bool setRecordingDirectory(const QString &dir);
+ bool setOutputFormat (RecordingConfig::OutputFormat of);
+ bool setPreRecording (bool enable, int seconds);
+ bool setRecordingConfig (const RecordingConfig &cfg);
+
+ void getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const;
+ const SoundFormat &getSoundFormat () const;
+ int getMP3Quality () const;
+ float getOggQuality () const;
+ const QString &getRecordingDirectory() const;
+ RecordingConfig::OutputFormat getOutputFormat() const;
+ bool getPreRecording(int &seconds) const;
+ const RecordingConfig &getRecordingConfig() const;
+
+// ISoundStreamClient
+
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool startPlayback(SoundStreamID id);
+ bool stopPlayback(SoundStreamID id);
+
+ bool startRecording(SoundStreamID id);
+ bool startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format);
+ bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md);
+ bool stopRecording(SoundStreamID id);
+ bool isRecordingRunning(SoundStreamID id, bool &b, SoundFormat &sf) const;
+
+ bool getSoundStreamDescription(SoundStreamID id, QString &descr) const;
+ bool getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const;
+
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamChanged(SoundStreamID id);
+
+ bool enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const;
+
+protected slots:
+
+ bool event(QEvent *e);
+
+protected:
+
+ bool startEncoder(SoundStreamID ssid, const RecordingConfig &cfg);
+ void stopEncoder(SoundStreamID ssid);
+
+protected:
+
+ RecordingConfig m_config;
+ QMap<SoundStreamID, FileRingBuffer*> m_PreRecordingBuffers;
+
+ QMap<SoundStreamID, RecordingEncoding*> m_EncodingThreads;
+ QMap<SoundStreamID, SoundStreamID> m_RawStreams2EncodedStreams;
+ QMap<SoundStreamID, SoundStreamID> m_EncodedStreams2RawStreams;
+};
+
+/* PreRecording Notes: listen for startplayback, stopplayback, closestream
+ manage map streamid => buffer
+ set each started stream into capture mode
+ put data into ringbuffers
+ on capture start, feed everything into the encoder buffer,
+ if encoderbuffer < prerecbuffer =>
+ put as much as possible into encoder
+ put new audio data into ring buffer
+
+*/
+
+#endif
diff --git a/kradio3/plugins/recording/soundstreamevent.h b/kradio3/plugins/recording/soundstreamevent.h
new file mode 100644
index 0000000..0cf6cdd
--- /dev/null
+++ b/kradio3/plugins/recording/soundstreamevent.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ soundstreamevent.h - description
+ -------------------
+ begin : Fri May 06 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_SOUNDSTREAM_EVENT_H
+#define KRADIO_RECORDING_SOUNDSTREAM_EVENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qevent.h>
+
+#include "../../src/include/sound_metadata.h"
+
+const QEvent::Type EncodingTerminated = (QEvent::Type)(QEvent::User+1);
+const QEvent::Type EncodingStep = (QEvent::Type)(QEvent::User+2);
+
+class SoundStreamEvent : public QEvent
+{
+public:
+ SoundStreamEvent(QEvent::Type t, SoundStreamID id) : QEvent(t), m_SSID(id) {}
+ const SoundStreamID &getSoundStreamID() const { return m_SSID; }
+
+ static bool isSoundStreamEvent (const QEvent *e) { return e && ((e->type() == EncodingTerminated) || (e->type() == EncodingStep)); }
+
+protected:
+ SoundStreamID m_SSID;
+};
+
+
+
+
+
+
+class SoundStreamEncodingTerminatedEvent : public SoundStreamEvent
+{
+public:
+ SoundStreamEncodingTerminatedEvent(SoundStreamID id) : SoundStreamEvent(EncodingTerminated, id) {}
+};
+
+
+
+
+
+
+class SoundStreamEncodingStepEvent : public SoundStreamEvent
+{
+public:
+ SoundStreamEncodingStepEvent(SoundStreamID id, const char *data, size_t size, const SoundMetaData &md)
+ : SoundStreamEvent(EncodingStep, id),
+ m_Size(size),
+ m_MetaData(md)
+ {
+ m_Data = new char [m_Size];
+ memcpy (m_Data, data, m_Size);
+ }
+ virtual ~SoundStreamEncodingStepEvent() { freeData(); }
+
+ void freeData() { if (m_Data) delete m_Data; m_Data = NULL; m_Size = 0; } // _MUST_ be called by event receiver
+
+ const char *data() const { return m_Data; }
+ size_t size() const { return m_Size; }
+ const SoundMetaData &metaData() const { return m_MetaData; }
+
+ static bool isSoundStreamEncodingStep (const QEvent *e) { return e && (e->type() == EncodingStep); }
+
+protected:
+ char *m_Data;
+ size_t m_Size;
+ SoundMetaData m_MetaData;
+};
+
+#endif
diff --git a/kradio3/plugins/soundserver/Makefile.am b/kradio3/plugins/soundserver/Makefile.am
new file mode 100644
index 0000000..17c5946
--- /dev/null
+++ b/kradio3/plugins/soundserver/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libsoundserver.la
+
+libsoundserver_la_SOURCES = soundserver.cpp
+libsoundserver_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = soundserver.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-sound-server.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-soundserver.pot
diff --git a/kradio3/plugins/soundserver/po/Makefile.am b/kradio3/plugins/soundserver/po/Makefile.am
new file mode 100644
index 0000000..22b977e
--- /dev/null
+++ b/kradio3/plugins/soundserver/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-soundserver
+POFILES = AUTO
diff --git a/kradio3/plugins/soundserver/po/de.po b/kradio3/plugins/soundserver/po/de.po
new file mode 100644
index 0000000..1d43376
--- /dev/null
+++ b/kradio3/plugins/soundserver/po/de.po
@@ -0,0 +1,29 @@
+# translation of de.po to
+# translation of kradio-sound-server.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-06 01:32+0100\n"
+"PO-Revision-Date: 2006-11-06 01:06+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: soundserver.cpp:27
+msgid "SoundServer"
+msgstr "SoundServer"
+
+#: soundserver.cpp:32
+msgid "SoundServer Plugin"
+msgstr "SoundServer Plugin"
+
+#: soundserver.cpp:34
+msgid "initializing kradio soundserver"
+msgstr "Initialisierung des KRadio-Soundservers"
diff --git a/kradio3/plugins/soundserver/po/ru.po b/kradio3/plugins/soundserver/po/ru.po
new file mode 100644
index 0000000..14b5bfc
--- /dev/null
+++ b/kradio3/plugins/soundserver/po/ru.po
@@ -0,0 +1,29 @@
+# translation of ru.po to
+# translation of kradio-soundserver.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 02:11+0100\n"
+"PO-Revision-Date: 2006-11-08 12:46+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#: soundserver.cpp:27
+msgid "SoundServer"
+msgstr "SoundServer"
+
+#: soundserver.cpp:32
+msgid "SoundServer Plugin"
+msgstr "Модуль звукового сервера"
+
+#: soundserver.cpp:34
+msgid "initializing kradio soundserver"
+msgstr "Включение звукового сервера KRadio"
diff --git a/kradio3/plugins/soundserver/soundserver.cpp b/kradio3/plugins/soundserver/soundserver.cpp
new file mode 100644
index 0000000..448bf14
--- /dev/null
+++ b/kradio3/plugins/soundserver/soundserver.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ soundserver.cpp - description
+ -------------------
+ begin : Sun Apr 17 2005
+ 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 "soundserver.h"
+
+#include <kapplication.h>
+#include <klocale.h>
+
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS(SoundServer, "kradio-soundserver", i18n("SoundServer"));
+
+/////////////////////////////////////////////////////////////////////////////
+
+SoundServer::SoundServer(const QString &name)
+ : PluginBase(name, i18n("SoundServer Plugin"))
+{
+ logDebug(i18n("initializing kradio soundserver"));
+}
+
+SoundServer::~SoundServer()
+{
+}
+
+bool SoundServer::connectI (Interface *i)
+{
+ bool a = PluginBase::connectI(i);
+ bool b = ISoundStreamServer::connectI(i);
+ return a || b;
+}
+
+
+bool SoundServer::disconnectI (Interface *i)
+{
+ bool a = PluginBase::disconnectI(i);
+ bool b = ISoundStreamServer::disconnectI(i);
+ return a || b;
+}
+
+
+
+void SoundServer::saveState (KConfig *) const
+{
+}
+
+void SoundServer::restoreState (KConfig *)
+{
+}
+
+ConfigPageInfo SoundServer::createConfigurationPage()
+{
+ return ConfigPageInfo ();
+}
+
+AboutPageInfo SoundServer::createAboutPage()
+{
+ return AboutPageInfo();
+}
diff --git a/kradio3/plugins/soundserver/soundserver.h b/kradio3/plugins/soundserver/soundserver.h
new file mode 100644
index 0000000..01f2377
--- /dev/null
+++ b/kradio3/plugins/soundserver/soundserver.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ soundserver.h - description
+ -------------------
+ begin : Sun Apr 17 2005
+ 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_SOUNDSERVER_H
+#define KRADIO_SOUNDSERVER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "../../src/include/plugins.h"
+
+
+class SoundServer : public PluginBase,
+ public ISoundStreamServer
+{
+public:
+ SoundServer(const QString &name);
+ ~SoundServer();
+
+ virtual bool connectI (Interface *);
+ virtual bool disconnectI (Interface *);
+
+ virtual QString pluginClassName() const { return "SoundServer"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+};
+
+#endif
diff --git a/kradio3/plugins/streaming/Makefile.am b/kradio3/plugins/streaming/Makefile.am
new file mode 100644
index 0000000..0e5ed11
--- /dev/null
+++ b/kradio3/plugins/streaming/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libstreaming.la
+libstreaming_la_SOURCES = streaming.cpp streaming-configuration-ui.ui \
+ streaming-configuration.cpp streaming-job.cpp
+libstreaming_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = streaming.h streaming-configuration.h streaming-job.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-streaming.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-streaming.pot
diff --git a/kradio3/plugins/streaming/icons/Makefile.am b/kradio3/plugins/streaming/icons/Makefile.am
new file mode 100644
index 0000000..b3f2583
--- /dev/null
+++ b/kradio3/plugins/streaming/icons/Makefile.am
@@ -0,0 +1,2 @@
+icons_ICON = AUTO
+iconsdir = $(kde_datadir)/kradio/icons
diff --git a/kradio3/plugins/streaming/icons/hi16-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi16-action-kradio_streaming.png
new file mode 100644
index 0000000..af7de60
--- /dev/null
+++ b/kradio3/plugins/streaming/icons/hi16-action-kradio_streaming.png
Binary files differ
diff --git a/kradio3/plugins/streaming/icons/hi22-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi22-action-kradio_streaming.png
new file mode 100644
index 0000000..c737464
--- /dev/null
+++ b/kradio3/plugins/streaming/icons/hi22-action-kradio_streaming.png
Binary files differ
diff --git a/kradio3/plugins/streaming/icons/hi32-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi32-action-kradio_streaming.png
new file mode 100644
index 0000000..d3ce851
--- /dev/null
+++ b/kradio3/plugins/streaming/icons/hi32-action-kradio_streaming.png
Binary files differ
diff --git a/kradio3/plugins/streaming/icons/hi48-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi48-action-kradio_streaming.png
new file mode 100644
index 0000000..2e1ff2a
--- /dev/null
+++ b/kradio3/plugins/streaming/icons/hi48-action-kradio_streaming.png
Binary files differ
diff --git a/kradio3/plugins/streaming/icons/hi64-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi64-action-kradio_streaming.png
new file mode 100644
index 0000000..465cda6
--- /dev/null
+++ b/kradio3/plugins/streaming/icons/hi64-action-kradio_streaming.png
Binary files differ
diff --git a/kradio3/plugins/streaming/po/Makefile.am b/kradio3/plugins/streaming/po/Makefile.am
new file mode 100644
index 0000000..e1b5685
--- /dev/null
+++ b/kradio3/plugins/streaming/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-streaming
+POFILES = AUTO
diff --git a/kradio3/plugins/streaming/po/de.po b/kradio3/plugins/streaming/po/de.po
new file mode 100644
index 0000000..aaa1e2e
--- /dev/null
+++ b/kradio3/plugins/streaming/po/de.po
@@ -0,0 +1,226 @@
+# translation of de.po to
+# translation of kradio-streaming.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:41+0100\n"
+"PO-Revision-Date: 2006-11-12 18:24+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file streaming-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:95 streaming-configuration-ui.cpp:253
+#, no-c-format
+msgid "StreamingConfigurationUI"
+msgstr "StreamingConfigurationUI"
+
+#. i18n: file streaming-configuration-ui.ui line 33
+#. i18n: file streaming-configuration-ui.ui line 74
+#. i18n: file streaming-configuration-ui.ui line 33
+#. i18n: file streaming-configuration-ui.ui line 74
+#: rc.cpp:6 rc.cpp:12 rc.cpp:98 rc.cpp:104 streaming-configuration-ui.cpp:43
+#: streaming-configuration-ui.cpp:52 streaming-configuration-ui.cpp:254
+#: streaming-configuration-ui.cpp:256
+#, no-c-format
+msgid "No."
+msgstr "Nr."
+
+#. i18n: file streaming-configuration-ui.ui line 44
+#. i18n: file streaming-configuration-ui.ui line 85
+#. i18n: file streaming-configuration-ui.ui line 44
+#. i18n: file streaming-configuration-ui.ui line 85
+#: rc.cpp:9 rc.cpp:15 rc.cpp:101 rc.cpp:107 streaming-configuration-ui.cpp:44
+#: streaming-configuration-ui.cpp:53 streaming-configuration-ui.cpp:255
+#: streaming-configuration-ui.cpp:257
+#, no-c-format
+msgid "URL"
+msgstr "URL"
+
+#. i18n: file streaming-configuration-ui.ui line 114
+#: rc.cpp:18 rc.cpp:110 streaming-configuration-ui.cpp:258
+#, no-c-format
+msgid "Capture URLs"
+msgstr "Aufnahme-URL"
+
+#. i18n: file streaming-configuration-ui.ui line 122
+#: rc.cpp:21 rc.cpp:113 streaming-configuration-ui.cpp:259
+#, no-c-format
+msgid "Playback URLs"
+msgstr "Wiedergabe-URL"
+
+#. i18n: file streaming-configuration-ui.ui line 434
+#: rc.cpp:32 rc.cpp:124 streaming-configuration-ui.cpp:268
+#, no-c-format
+msgid "URL Properties"
+msgstr "URL-Eigenschaften"
+
+#. i18n: file streaming-configuration-ui.ui line 446
+#: rc.cpp:35 rc.cpp:127 streaming-configuration-ui.cpp:270
+#, no-c-format
+msgid "Stereo"
+msgstr "Stereo"
+
+#. i18n: file streaming-configuration-ui.ui line 451
+#: rc.cpp:38 rc.cpp:130 streaming-configuration-ui.cpp:271
+#, no-c-format
+msgid "Mono"
+msgstr "Mono"
+
+#. i18n: file streaming-configuration-ui.ui line 471
+#: rc.cpp:41 rc.cpp:133 streaming-configuration-ui.cpp:272
+#, no-c-format
+msgid "Sample Bits"
+msgstr "Quantisierungs-Bits"
+
+#. i18n: file streaming-configuration-ui.ui line 479
+#: rc.cpp:44 rc.cpp:136 streaming-configuration-ui.cpp:273
+#, no-c-format
+msgid "Channels"
+msgstr "Kanäle"
+
+#. i18n: file streaming-configuration-ui.ui line 487
+#: rc.cpp:47 rc.cpp:139 streaming-configuration-ui.cpp:274
+#, no-c-format
+msgid "Endianess"
+msgstr "Byte-Reihenfolge"
+
+#. i18n: file streaming-configuration-ui.ui line 493
+#: rc.cpp:50 rc.cpp:142 streaming-configuration-ui.cpp:276
+#, no-c-format
+msgid "Little Endian"
+msgstr "Little Endian"
+
+#. i18n: file streaming-configuration-ui.ui line 498
+#: rc.cpp:53 rc.cpp:145 streaming-configuration-ui.cpp:277
+#, no-c-format
+msgid "Big Endian"
+msgstr "Big Endian"
+
+#. i18n: file streaming-configuration-ui.ui line 516
+#: rc.cpp:56 rc.cpp:148 streaming-configuration-ui.cpp:279
+#, no-c-format
+msgid "48000"
+msgstr "48000"
+
+#. i18n: file streaming-configuration-ui.ui line 521
+#: rc.cpp:59 rc.cpp:151 streaming-configuration-ui.cpp:280
+#, no-c-format
+msgid "44100"
+msgstr "44100"
+
+#. i18n: file streaming-configuration-ui.ui line 526
+#: rc.cpp:62 rc.cpp:154 streaming-configuration-ui.cpp:281
+#, no-c-format
+msgid "22050"
+msgstr "22050"
+
+#. i18n: file streaming-configuration-ui.ui line 531
+#: rc.cpp:65 rc.cpp:157 streaming-configuration-ui.cpp:282
+#, no-c-format
+msgid "11025"
+msgstr "11025"
+
+#. i18n: file streaming-configuration-ui.ui line 549
+#: rc.cpp:68 rc.cpp:160 streaming-configuration-ui.cpp:284
+#, no-c-format
+msgid "16"
+msgstr "16"
+
+#. i18n: file streaming-configuration-ui.ui line 554
+#: rc.cpp:71 rc.cpp:163 streaming-configuration-ui.cpp:285
+#, no-c-format
+msgid "8"
+msgstr "8"
+
+#. i18n: file streaming-configuration-ui.ui line 572
+#: rc.cpp:74 rc.cpp:166 streaming-configuration-ui.cpp:287
+#, no-c-format
+msgid "Raw"
+msgstr "Rohdaten"
+
+#. i18n: file streaming-configuration-ui.ui line 592
+#: rc.cpp:77 rc.cpp:169 streaming-configuration-ui.cpp:288
+#, no-c-format
+msgid "kB"
+msgstr "kB"
+
+#. i18n: file streaming-configuration-ui.ui line 609
+#: rc.cpp:80 rc.cpp:172 streaming-configuration-ui.cpp:289
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Puffergröße"
+
+#. i18n: file streaming-configuration-ui.ui line 617
+#: rc.cpp:83 rc.cpp:175 streaming-configuration-ui.cpp:290
+#, no-c-format
+msgid "Format"
+msgstr "Format"
+
+#. i18n: file streaming-configuration-ui.ui line 625
+#: rc.cpp:86 rc.cpp:178 streaming-configuration-ui.cpp:291
+#, no-c-format
+msgid "Sample Rate"
+msgstr "Abtastrate"
+
+#. i18n: file streaming-configuration-ui.ui line 631
+#: rc.cpp:89 rc.cpp:181 streaming-configuration-ui.cpp:293
+#, no-c-format
+msgid "Signed"
+msgstr "Vorzeichenbehaftet"
+
+#. i18n: file streaming-configuration-ui.ui line 636
+#: rc.cpp:92 rc.cpp:184 streaming-configuration-ui.cpp:294
+#, no-c-format
+msgid "Unsigned"
+msgstr "Vorzeichenlos"
+
+#: streaming-configuration.cpp:155 streaming-configuration.cpp:259
+msgid "new channel"
+msgstr "Neuer Kanal"
+
+#: streaming-job.cpp:204
+msgid "skipped %1 bytes"
+msgstr "%1 bytes wurden übersprungen"
+
+#: streaming.cpp:33
+msgid "Streaming Support"
+msgstr "Unterstützung für das Streaming"
+
+#: streaming.cpp:42
+msgid "KRadio Streaming Plugin"
+msgstr "KRadio Streaming-Plugin"
+
+#: streaming.cpp:172
+msgid "Streaming"
+msgstr "Streaming"
+
+#: streaming.cpp:173
+msgid "Streaming Device Options"
+msgstr "Geräteoptionen für das Streaming"
+
+#: streaming.cpp:393
+msgid "internal stream, not stored (%1)"
+msgstr "interner, nicht aufgezeichneter Datenstrom (%1)"
+
+#: streaming.cpp:403
+msgid ""
+"StreamingDevice %1::notifySoundStreamData: Playback Clients skipped %2 bytes"
+msgstr ""
+"Streaminggerät %1::notifySoundStreamData: Die Wiedergabe-Module haben %2 "
+"bytes übersprungen."
+
+#: streaming.cpp:426
+msgid "Streaming Device %1"
+msgstr "Streaming-Gerät %1"
+
+#: streaming.cpp:432 streaming.cpp:437
+msgid "Streaming Device %1, %2: %3"
+msgstr "Streaming-Gerät %1, %2: %3"
diff --git a/kradio3/plugins/streaming/po/ru.po b/kradio3/plugins/streaming/po/ru.po
new file mode 100644
index 0000000..c46978a
--- /dev/null
+++ b/kradio3/plugins/streaming/po/ru.po
@@ -0,0 +1,228 @@
+# translation of ru.po to
+# translation of kradio-streaming.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:20+0100\n"
+"PO-Revision-Date: 2006-11-08 12:25+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file streaming-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:95 streaming-configuration-ui.cpp:253
+#, no-c-format
+msgid "StreamingConfigurationUI"
+msgstr "StreamingConfigurationUI"
+
+#. i18n: file streaming-configuration-ui.ui line 33
+#. i18n: file streaming-configuration-ui.ui line 74
+#. i18n: file streaming-configuration-ui.ui line 33
+#. i18n: file streaming-configuration-ui.ui line 74
+#: rc.cpp:6 rc.cpp:12 rc.cpp:98 rc.cpp:104 streaming-configuration-ui.cpp:43
+#: streaming-configuration-ui.cpp:52 streaming-configuration-ui.cpp:254
+#: streaming-configuration-ui.cpp:256
+#, no-c-format
+msgid "No."
+msgstr "No "
+
+#. i18n: file streaming-configuration-ui.ui line 44
+#. i18n: file streaming-configuration-ui.ui line 85
+#. i18n: file streaming-configuration-ui.ui line 44
+#. i18n: file streaming-configuration-ui.ui line 85
+#: rc.cpp:9 rc.cpp:15 rc.cpp:101 rc.cpp:107 streaming-configuration-ui.cpp:44
+#: streaming-configuration-ui.cpp:53 streaming-configuration-ui.cpp:255
+#: streaming-configuration-ui.cpp:257
+#, no-c-format
+msgid "URL"
+msgstr "Адрес"
+
+#. i18n: file streaming-configuration-ui.ui line 114
+#: rc.cpp:18 rc.cpp:110 streaming-configuration-ui.cpp:258
+#, no-c-format
+msgid "Capture URLs"
+msgstr "Адреса для записи"
+
+#. i18n: file streaming-configuration-ui.ui line 122
+#: rc.cpp:21 rc.cpp:113 streaming-configuration-ui.cpp:259
+#, no-c-format
+msgid "Playback URLs"
+msgstr "Адреса для воспроизведения"
+
+#. i18n: file streaming-configuration-ui.ui line 434
+#: rc.cpp:32 rc.cpp:124 streaming-configuration-ui.cpp:268
+#, no-c-format
+msgid "URL Properties"
+msgstr "Параметры для URL"
+
+#. i18n: file streaming-configuration-ui.ui line 446
+#: rc.cpp:35 rc.cpp:127 streaming-configuration-ui.cpp:270
+#, no-c-format
+msgid "Stereo"
+msgstr "2 (Стерео)"
+
+#. i18n: file streaming-configuration-ui.ui line 451
+#: rc.cpp:38 rc.cpp:130 streaming-configuration-ui.cpp:271
+#, no-c-format
+msgid "Mono"
+msgstr "1 (Моно)"
+
+#. i18n: file streaming-configuration-ui.ui line 471
+#: rc.cpp:41 rc.cpp:133 streaming-configuration-ui.cpp:272
+#, no-c-format
+msgid "Sample Bits"
+msgstr "Бит на элемент выборки"
+
+#. i18n: file streaming-configuration-ui.ui line 479
+#: rc.cpp:44 rc.cpp:136 streaming-configuration-ui.cpp:273
+#, no-c-format
+msgid "Channels"
+msgstr "Число каналов"
+
+#. i18n: file streaming-configuration-ui.ui line 487
+#: rc.cpp:47 rc.cpp:139 streaming-configuration-ui.cpp:274
+#, no-c-format
+msgid "Endianess"
+msgstr "Порядок байтов"
+
+#. i18n: file streaming-configuration-ui.ui line 493
+#: rc.cpp:50 rc.cpp:142 streaming-configuration-ui.cpp:276
+#, no-c-format
+msgid "Little Endian"
+msgstr "Little Endian"
+
+#. i18n: file streaming-configuration-ui.ui line 498
+#: rc.cpp:53 rc.cpp:145 streaming-configuration-ui.cpp:277
+#, no-c-format
+msgid "Big Endian"
+msgstr "Big Endian"
+
+#. i18n: file streaming-configuration-ui.ui line 516
+#: rc.cpp:56 rc.cpp:148 streaming-configuration-ui.cpp:279
+#, no-c-format
+msgid "48000"
+msgstr "48000"
+
+#. i18n: file streaming-configuration-ui.ui line 521
+#: rc.cpp:59 rc.cpp:151 streaming-configuration-ui.cpp:280
+#, no-c-format
+msgid "44100"
+msgstr "44100"
+
+#. i18n: file streaming-configuration-ui.ui line 526
+#: rc.cpp:62 rc.cpp:154 streaming-configuration-ui.cpp:281
+#, no-c-format
+msgid "22050"
+msgstr "22050"
+
+#. i18n: file streaming-configuration-ui.ui line 531
+#: rc.cpp:65 rc.cpp:157 streaming-configuration-ui.cpp:282
+#, no-c-format
+msgid "11025"
+msgstr "11025"
+
+#. i18n: file streaming-configuration-ui.ui line 549
+#: rc.cpp:68 rc.cpp:160 streaming-configuration-ui.cpp:284
+#, no-c-format
+msgid "16"
+msgstr "16"
+
+#. i18n: file streaming-configuration-ui.ui line 554
+#: rc.cpp:71 rc.cpp:163 streaming-configuration-ui.cpp:285
+#, no-c-format
+msgid "8"
+msgstr "8"
+
+#. i18n: file streaming-configuration-ui.ui line 572
+#: rc.cpp:74 rc.cpp:166 streaming-configuration-ui.cpp:287
+#, no-c-format
+msgid "Raw"
+msgstr "Raw"
+
+#. i18n: file streaming-configuration-ui.ui line 592
+#: rc.cpp:77 rc.cpp:169 streaming-configuration-ui.cpp:288
+#, no-c-format
+msgid "kB"
+msgstr "kB"
+
+#. i18n: file streaming-configuration-ui.ui line 609
+#: rc.cpp:80 rc.cpp:172 streaming-configuration-ui.cpp:289
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Размер буфера"
+
+#. i18n: file streaming-configuration-ui.ui line 617
+#: rc.cpp:83 rc.cpp:175 streaming-configuration-ui.cpp:290
+#, no-c-format
+msgid "Format"
+msgstr "Формат"
+
+#. i18n: file streaming-configuration-ui.ui line 625
+#: rc.cpp:86 rc.cpp:178 streaming-configuration-ui.cpp:291
+#, no-c-format
+msgid "Sample Rate"
+msgstr "Частота дискретизации"
+
+#. i18n: file streaming-configuration-ui.ui line 631
+#: rc.cpp:89 rc.cpp:181 streaming-configuration-ui.cpp:293
+#, no-c-format
+msgid "Signed"
+msgstr "Со знаком"
+
+#. i18n: file streaming-configuration-ui.ui line 636
+#: rc.cpp:92 rc.cpp:184 streaming-configuration-ui.cpp:294
+#, no-c-format
+msgid "Unsigned"
+msgstr "Без знака"
+
+#: streaming-configuration.cpp:155 streaming-configuration.cpp:259
+msgid "new channel"
+msgstr "новый канал"
+
+#: streaming-job.cpp:204
+msgid "skipped %1 bytes"
+msgstr "Пропущено %1 байт"
+
+#: streaming.cpp:33
+msgid "Streaming Support"
+msgstr ""
+"Сетевое\n"
+"вещание"
+
+#: streaming.cpp:42
+msgid "KRadio Streaming Plugin"
+msgstr "Модуль сетевого вещания для KRadio"
+
+#: streaming.cpp:172
+msgid "Streaming"
+msgstr ""
+"Сетевое\n"
+"вещание"
+
+#: streaming.cpp:173
+msgid "Streaming Device Options"
+msgstr "Параметры сетевого вещания"
+
+#: streaming.cpp:393
+msgid "internal stream, not stored (%1)"
+msgstr ""
+
+#: streaming.cpp:403
+msgid ""
+"StreamingDevice %1::notifySoundStreamData: Playback Clients skipped %2 bytes"
+msgstr "StreamingDevice %1::notifySoundStreamData: Клиенты пропустили %2 байт"
+
+#: streaming.cpp:426
+msgid "Streaming Device %1"
+msgstr "Устройство вещания %1"
+
+#: streaming.cpp:432 streaming.cpp:437
+msgid "Streaming Device %1, %2: %3"
+msgstr "Устройство вещания %1, %2: %3"
diff --git a/kradio3/plugins/streaming/streaming-configuration-ui.ui b/kradio3/plugins/streaming/streaming-configuration-ui.ui
new file mode 100644
index 0000000..001d4ae
--- /dev/null
+++ b/kradio3/plugins/streaming/streaming-configuration-ui.ui
@@ -0,0 +1,777 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>StreamingConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>StreamingConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>397</width>
+ <height>423</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>StreamingConfigurationUI</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout48</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView" row="1" column="0">
+ <column>
+ <property name="text">
+ <string>No.</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_ListPlaybackURLs</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="selectionMode" stdset="0">
+ <enum>Single</enum>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ </widget>
+ <widget class="KListView" row="1" column="2">
+ <column>
+ <property name="text">
+ <string>No.</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_ListCaptureURLs</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Capture URLs</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Playback URLs</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="3">
+ <property name="name">
+ <cstring>layout38_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbNewCaptureURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"filenew2"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbDeleteCaptureURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"editdelete"</iconset>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer46_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>10</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbUpCaptureURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"1uparrow"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbDownCaptureURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"1downarrow"</iconset>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>layout38</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbNewPlaybackURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"filenew2"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbDeletePlaybackURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"editdelete"</iconset>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer46</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>10</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbUpPlaybackURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"1uparrow"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_pbDownPlaybackURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"1downarrow"</iconset>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>URL Properties</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>10</number>
+ </property>
+ <widget class="KComboBox" row="5" column="1">
+ <item>
+ <property name="text">
+ <string>Stereo</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mono</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_cbChannels</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>lableBits</cstring>
+ </property>
+ <property name="text">
+ <string>Sample Bits</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>lableChannels</cstring>
+ </property>
+ <property name="text">
+ <string>Channels</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>lableEndianess</cstring>
+ </property>
+ <property name="text">
+ <string>Endianess</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="4" column="1">
+ <item>
+ <property name="text">
+ <string>Little Endian</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Big Endian</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_cbEndianess</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>48000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>44100</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>22050</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>11025</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_cbRate</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>16</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>8</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_cbBits</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Raw</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_cbFormat</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_sbBufferSize</cstring>
+ </property>
+ <property name="suffix">
+ <string>kB</string>
+ </property>
+ <property name="maxValue">
+ <number>1024</number>
+ </property>
+ <property name="minValue">
+ <number>4</number>
+ </property>
+ <property name="lineStep">
+ <number>4</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelRate_2</cstring>
+ </property>
+ <property name="text">
+ <string>Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>labelRate_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Format</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>labelRate</cstring>
+ </property>
+ <property name="text">
+ <string>Sample Rate</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="2">
+ <item>
+ <property name="text">
+ <string>Signed</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Unsigned</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_cbSign</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>spacer1_4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>spacer1_4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="4" column="2">
+ <property name="name">
+ <cstring>spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="5" column="2">
+ <property name="name">
+ <cstring>spacer1_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>m_ListPlaybackURLs</tabstop>
+ <tabstop>m_pbNewPlaybackURL</tabstop>
+ <tabstop>m_pbDeletePlaybackURL</tabstop>
+ <tabstop>m_pbUpPlaybackURL</tabstop>
+ <tabstop>m_pbDownPlaybackURL</tabstop>
+ <tabstop>m_ListCaptureURLs</tabstop>
+ <tabstop>m_pbNewCaptureURL</tabstop>
+ <tabstop>m_pbDeleteCaptureURL</tabstop>
+ <tabstop>m_pbUpCaptureURL</tabstop>
+ <tabstop>m_pbDownCaptureURL</tabstop>
+ <tabstop>m_sbBufferSize</tabstop>
+ <tabstop>m_cbFormat</tabstop>
+ <tabstop>m_cbRate</tabstop>
+ <tabstop>m_cbBits</tabstop>
+ <tabstop>m_cbSign</tabstop>
+ <tabstop>m_cbEndianess</tabstop>
+ <tabstop>m_cbChannels</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+</includes>
+<pixmapfunction>SmallIconSet</pixmapfunction>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+ <includehint>klistview.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kcombobox.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/streaming/streaming-configuration.cpp b/kradio3/plugins/streaming/streaming-configuration.cpp
new file mode 100644
index 0000000..ea1801d
--- /dev/null
+++ b/kradio3/plugins/streaming/streaming-configuration.cpp
@@ -0,0 +1,567 @@
+/***************************************************************************
+ streaming-configuration.cpp - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 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 <qcheckbox.h>
+
+#include <kurlrequester.h>
+#include <knuminput.h>
+#include <klistview.h>
+#include <kcombobox.h>
+#include <knuminput.h>
+
+#include <klocale.h>
+
+#include "streaming-configuration.h"
+#include "streaming.h"
+
+StreamingConfiguration::StreamingConfiguration (QWidget *parent, StreamingDevice *streamer)
+ : StreamingConfigurationUI(parent),
+ m_ignore_updates(false),
+ m_dirty(true),
+ m_StreamingDevice(streamer)
+{
+ connect(m_pbNewPlaybackURL, SIGNAL(clicked()), this, SLOT(slotNewPlaybackChannel()));
+ connect(m_pbDeletePlaybackURL, SIGNAL(clicked()), this, SLOT(slotDeletePlaybackChannel()));
+ connect(m_pbUpPlaybackURL, SIGNAL(clicked()), this, SLOT(slotUpPlaybackChannel()));
+ connect(m_pbDownPlaybackURL, SIGNAL(clicked()), this, SLOT(slotDownPlaybackChannel()));
+ connect(m_ListPlaybackURLs, SIGNAL(selectionChanged()), this, SLOT(slotPlaybackSelectionChanged()));
+ connect(m_ListPlaybackURLs, SIGNAL(itemRenamed(QListViewItem *)), this, SLOT(slotSetDirty()));
+
+ connect(m_pbNewCaptureURL, SIGNAL(clicked()), this, SLOT(slotNewCaptureChannel()));
+ connect(m_pbDeleteCaptureURL, SIGNAL(clicked()), this, SLOT(slotDeleteCaptureChannel()));
+ connect(m_pbUpCaptureURL, SIGNAL(clicked()), this, SLOT(slotUpCaptureChannel()));
+ connect(m_pbDownCaptureURL, SIGNAL(clicked()), this, SLOT(slotDownCaptureChannel()));
+ connect(m_ListCaptureURLs, SIGNAL(selectionChanged()), this, SLOT(slotCaptureSelectionChanged()));
+ connect(m_ListCaptureURLs, SIGNAL(itemRenamed(QListViewItem *)), this, SLOT(slotSetDirty()));
+
+ connect(m_cbBits, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat()));
+ connect(m_cbChannels, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat()));
+ connect(m_cbEndianess, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat()));
+ connect(m_cbFormat, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat()));
+ connect(m_cbRate, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat()));
+ connect(m_cbSign, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat()));
+ connect(m_sbBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateSoundFormat()));
+
+ m_ListPlaybackURLs->setAllColumnsShowFocus(true);
+ m_ListPlaybackURLs->setSorting(-1);
+ m_ListCaptureURLs->setAllColumnsShowFocus(true);
+ m_ListCaptureURLs->setSorting(-1);
+
+ slotCancel();
+}
+
+
+StreamingConfiguration::~StreamingConfiguration ()
+{
+}
+
+
+void StreamingConfiguration::slotOK()
+{
+ if (!m_dirty)
+ return;
+
+ m_StreamingDevice->resetPlaybackStreams(false);
+ m_StreamingDevice->resetCaptureStreams(false);
+
+ QListViewItem *item = m_ListPlaybackURLs->firstChild();
+ for (int i = 0; item; ++i, item = item->nextSibling()) {
+ m_StreamingDevice->addPlaybackStream(item->text(1), m_PlaybackSoundFormats[i], m_PlaybackBufferSizes[i], !item->nextSibling());
+ }
+
+ item = m_ListCaptureURLs->firstChild();
+ for (int i = 0; item; ++i, item = item->nextSibling()) {
+ m_StreamingDevice->addCaptureStream(item->text(1), m_CaptureSoundFormats[i], m_CaptureBufferSizes[i], !item->nextSibling());
+ }
+
+ m_dirty = false;
+}
+
+
+void StreamingConfiguration::slotCancel()
+{
+ if (!m_dirty)
+ return;
+
+ const QStringList &playbackChannels = m_StreamingDevice->getPlaybackChannels();
+ const QStringList &captureChannels = m_StreamingDevice->getCaptureChannels();
+
+ m_ListPlaybackURLs->clear();
+ m_PlaybackBufferSizes.clear();
+ m_PlaybackSoundFormats.clear();
+
+ for (unsigned int i = 0; i < playbackChannels.size(); ++i) {
+ SoundFormat sf;
+ size_t buffer_size;
+ QString url;
+ m_StreamingDevice->getPlaybackStreamOptions(playbackChannels[i], url, sf, buffer_size);
+ m_PlaybackSoundFormats.append(sf);
+ m_PlaybackBufferSizes.append(buffer_size);
+
+ QListViewItem *item = new QListViewItem(m_ListPlaybackURLs, m_ListPlaybackURLs->lastChild());
+ item->setText(0, QString::number(m_ListPlaybackURLs->childCount()));
+ item->setText(1, url);
+ item->setRenameEnabled(1, true);
+ }
+
+ m_ListCaptureURLs->clear();
+ m_CaptureBufferSizes.clear();
+ m_CaptureSoundFormats.clear();
+
+ for (unsigned int i = 0; i < captureChannels.size(); ++i) {
+ SoundFormat sf;
+ size_t buffer_size;
+ QString url;
+ m_StreamingDevice->getCaptureStreamOptions(captureChannels[i], url, sf, buffer_size);
+ m_CaptureSoundFormats.append(sf);
+ m_CaptureBufferSizes.append(buffer_size);
+
+ QListViewItem *item = new QListViewItem(m_ListCaptureURLs, m_ListCaptureURLs->lastChild());
+ item->setText(0, QString::number(m_ListCaptureURLs->childCount()));
+ item->setText(1, url);
+ item->setRenameEnabled(1, true);
+ }
+ slotPlaybackSelectionChanged();
+ slotCaptureSelectionChanged();
+
+ m_dirty = false;
+}
+
+void StreamingConfiguration::slotUpdateConfig()
+{
+ slotSetDirty();
+ slotCancel();
+}
+
+void StreamingConfiguration::slotNewPlaybackChannel()
+{
+ slotSetDirty();
+ QListViewItem *item = new QListViewItem(m_ListPlaybackURLs, m_ListPlaybackURLs->lastChild());
+ item->setText(0, QString::number(m_ListPlaybackURLs->childCount()));
+ item->setText(1, i18n("new channel"));
+ item->setRenameEnabled(1,true);
+ item->startRename(1);
+
+ m_PlaybackSoundFormats.append(SoundFormat());
+ m_PlaybackBufferSizes.append(64*1024);
+ int n = m_PlaybackSoundFormats.size();
+ setStreamOptions(m_PlaybackSoundFormats[n-1], m_PlaybackBufferSizes[n-1]);
+}
+
+
+void StreamingConfiguration::slotDeletePlaybackChannel()
+{
+ slotSetDirty();
+ QListViewItem *item = m_ListPlaybackURLs->selectedItem();
+ if (item) {
+ int idx = 0;
+ QListViewItem *i = m_ListPlaybackURLs->firstChild(),
+ *prev = NULL,
+ *next = item->nextSibling();
+ for (; i && i != item; i = i->nextSibling()) {
+ prev = i;
+ ++idx;
+ }
+ if(next) {
+ m_ListPlaybackURLs->setSelected(next, true);
+ } else if (prev){
+ m_ListPlaybackURLs->setSelected(prev, true);
+ }
+ int x = item->text(0).toUInt();
+ for (i = next; i; i = i->nextSibling(), ++x) {
+ i->setText(0, QString::number(x));
+ }
+ m_ListPlaybackURLs->takeItem(item);
+ delete item;
+
+ int n = m_PlaybackSoundFormats.size();
+ m_PlaybackSoundFormats.remove(m_PlaybackSoundFormats.at(idx));
+ m_PlaybackBufferSizes .remove(m_PlaybackBufferSizes.at(idx));
+ idx = idx < n - 1 ? idx : n - 1;
+ setStreamOptions( m_PlaybackSoundFormats[idx], m_PlaybackBufferSizes[idx]);
+ slotPlaybackSelectionChanged();
+ }
+}
+
+
+void StreamingConfiguration::slotUpPlaybackChannel()
+{
+ slotSetDirty();
+ QListViewItem *prev = NULL;
+ QListViewItem *i = m_ListPlaybackURLs->firstChild();
+ QListViewItem *item = m_ListPlaybackURLs->selectedItem();
+ int idx = 0;
+ for (; i && i != item; i = i->nextSibling(), ++idx) {
+ prev = i;
+ }
+ if (prev && item) {
+ QString s = prev->text(1);
+ prev->setText(1, item->text(1));
+ item->setText(1, s);
+ SoundFormat sf = m_PlaybackSoundFormats[idx];
+ m_PlaybackSoundFormats[idx] = m_PlaybackSoundFormats[idx-1];
+ m_PlaybackSoundFormats[idx-1] = sf;
+ size_t size = m_PlaybackBufferSizes[idx];
+ m_PlaybackBufferSizes[idx] = m_PlaybackBufferSizes[idx-1];
+ m_PlaybackBufferSizes[idx-1] = size;
+ m_ListPlaybackURLs->setSelected(prev, true);
+ }
+ m_ListPlaybackURLs->ensureItemVisible(prev);
+}
+
+
+void StreamingConfiguration::slotDownPlaybackChannel()
+{
+ slotSetDirty();
+ QListViewItem *item = m_ListPlaybackURLs->selectedItem();
+ QListViewItem *next = item ? item->nextSibling() : NULL;
+ QListViewItem *i = m_ListPlaybackURLs->firstChild();
+ int idx = 0;
+ for (; i && i != item; i = i->nextSibling()) {
+ ++idx;
+ }
+ if (next && item) {
+ QString s = next->text(1);
+ next->setText(1, item->text(1));
+ item->setText(1, s);
+ SoundFormat sf = m_PlaybackSoundFormats[idx];
+ m_PlaybackSoundFormats[idx] = m_PlaybackSoundFormats[idx+1];
+ m_PlaybackSoundFormats[idx+1] = sf;
+ size_t size = m_PlaybackBufferSizes[idx];
+ m_PlaybackBufferSizes[idx] = m_PlaybackBufferSizes[idx+1];
+ m_PlaybackBufferSizes[idx+1] = size;
+ m_ListPlaybackURLs->setSelected(next, true);
+ }
+ m_ListPlaybackURLs->ensureItemVisible(next);
+}
+
+
+
+void StreamingConfiguration::slotNewCaptureChannel()
+{
+ slotSetDirty();
+ QListViewItem *item = new QListViewItem(m_ListCaptureURLs, m_ListCaptureURLs->lastChild());
+ item->setText(0, QString::number(m_ListCaptureURLs->childCount()));
+ item->setText(1, i18n("new channel"));
+ item->setRenameEnabled(1,true);
+ item->startRename(1);
+
+ m_CaptureSoundFormats.append(SoundFormat());
+ m_CaptureBufferSizes.append(64*1024);
+ int n = m_CaptureSoundFormats.size();
+ setStreamOptions(m_CaptureSoundFormats[n-1], m_CaptureBufferSizes[n-1]);
+}
+
+
+void StreamingConfiguration::slotDeleteCaptureChannel()
+{
+ slotSetDirty();
+ QListViewItem *item = m_ListCaptureURLs->selectedItem();
+ if (item) {
+ int idx = 0;
+ QListViewItem *i = m_ListCaptureURLs->firstChild(),
+ *prev = NULL,
+ *next = item->nextSibling();
+ for (; i && i != item; i = i->nextSibling()) {
+ prev = i;
+ ++idx;
+ }
+ if (next) {
+ m_ListCaptureURLs->setSelected(next, true);
+ } else if (prev){
+ m_ListCaptureURLs->setSelected(prev, true);
+ }
+ int x = item->text(0).toUInt();
+ for (i = next; i; i = i->nextSibling(), ++x) {
+ i->setText(0, QString::number(x));
+ }
+ m_ListCaptureURLs->takeItem(item);
+ delete item;
+
+ int n = m_CaptureSoundFormats.size();
+ m_CaptureSoundFormats.remove(m_CaptureSoundFormats.at(idx));
+ m_CaptureBufferSizes .remove(m_CaptureBufferSizes.at(idx));
+ idx = idx < n - 1 ? idx : n - 1;
+ setStreamOptions( m_CaptureSoundFormats[idx], m_CaptureBufferSizes[idx]);
+ slotCaptureSelectionChanged();
+ }
+}
+
+
+void StreamingConfiguration::slotUpCaptureChannel()
+{
+ slotSetDirty();
+ QListViewItem *prev = NULL;
+ QListViewItem *i = m_ListCaptureURLs->firstChild();
+ QListViewItem *item = m_ListCaptureURLs->selectedItem();
+ int idx = 0;
+ for (; i && i != item; i = i->nextSibling(), ++idx) {
+ prev = i;
+ }
+ if (prev && item) {
+ QString s = prev->text(1);
+ prev->setText(1, item->text(1));
+ item->setText(1, s);
+ SoundFormat sf = m_CaptureSoundFormats[idx];
+ m_CaptureSoundFormats[idx] = m_CaptureSoundFormats[idx-1];
+ m_CaptureSoundFormats[idx-1] = sf;
+ size_t size = m_CaptureBufferSizes[idx];
+ m_CaptureBufferSizes[idx] = m_CaptureBufferSizes[idx-1];
+ m_CaptureBufferSizes[idx-1] = size;
+ m_ListCaptureURLs->setSelected(prev, true);
+ }
+ m_ListCaptureURLs->ensureItemVisible(prev);
+}
+
+
+void StreamingConfiguration::slotDownCaptureChannel()
+{
+ slotSetDirty();
+ QListViewItem *item = m_ListCaptureURLs->selectedItem();
+ QListViewItem *next = item ? item->nextSibling() : NULL;
+ QListViewItem *i = m_ListCaptureURLs->firstChild();
+ int idx = 0;
+ for (; i && i != item; i = i->nextSibling()) {
+ ++idx;
+ }
+ if (next && item) {
+ QString s = next->text(1);
+ next->setText(1, item->text(1));
+ item->setText(1, s);
+ SoundFormat sf = m_CaptureSoundFormats[idx];
+ m_CaptureSoundFormats[idx] = m_CaptureSoundFormats[idx+1];
+ m_CaptureSoundFormats[idx+1] = sf;
+ size_t size = m_CaptureBufferSizes[idx];
+ m_CaptureBufferSizes[idx] = m_CaptureBufferSizes[idx+1];
+ m_CaptureBufferSizes[idx+1] = size;
+ m_ListCaptureURLs->setSelected(next, true);
+ }
+ m_ListCaptureURLs->ensureItemVisible(next);
+}
+
+
+
+
+
+void StreamingConfiguration::slotPlaybackSelectionChanged()
+{
+ QListViewItem *item = m_ListPlaybackURLs->selectedItem();
+ bool up_possible = false;
+ bool down_possible = false;
+ if (item) {
+ int idx = 0;
+ QListViewItem *i = m_ListPlaybackURLs->firstChild();
+ for (; i && i != item; i = i->nextSibling()) {
+ ++idx;
+ }
+ up_possible = idx > 0;
+ down_possible = idx < m_ListPlaybackURLs->childCount() - 1;
+ setStreamOptions(m_PlaybackSoundFormats[idx], m_PlaybackBufferSizes[idx]);
+
+ item = m_ListCaptureURLs->selectedItem();
+ if (item)
+ m_ListCaptureURLs->setSelected(item, false);
+ }
+ QListViewItem *playback_item = m_ListPlaybackURLs->selectedItem();
+ QListViewItem *capture_item = m_ListCaptureURLs->selectedItem();
+ bool e = (playback_item || capture_item);
+ m_cbFormat ->setEnabled(e);
+ m_cbRate ->setEnabled(e);
+ m_cbBits ->setEnabled(e);
+ m_cbSign ->setEnabled(e);
+ m_cbChannels ->setEnabled(e);
+ m_cbEndianess ->setEnabled(e);
+ m_sbBufferSize->setEnabled(e);
+ m_pbUpPlaybackURL ->setEnabled(up_possible);
+ m_pbDownPlaybackURL->setEnabled(down_possible);
+}
+
+
+void StreamingConfiguration::slotCaptureSelectionChanged()
+{
+ QListViewItem *item = m_ListCaptureURLs->selectedItem();
+ bool up_possible = false;
+ bool down_possible = false;
+ if (item) {
+ int idx = 0;
+ QListViewItem *i = m_ListCaptureURLs->firstChild();
+ for (; i && i != item; i = i->nextSibling()) {
+ ++idx;
+ }
+ up_possible = idx > 0;
+ down_possible = idx < m_ListCaptureURLs->childCount() - 1;
+ setStreamOptions(m_CaptureSoundFormats[idx], m_CaptureBufferSizes[idx]);
+
+ item = m_ListPlaybackURLs->selectedItem();
+ if (item)
+ m_ListPlaybackURLs->setSelected(item, false);
+ }
+ QListViewItem *playback_item = m_ListPlaybackURLs->selectedItem();
+ QListViewItem *capture_item = m_ListCaptureURLs->selectedItem();
+ bool e = (playback_item || capture_item);
+ m_cbFormat ->setEnabled(e);
+ m_cbRate ->setEnabled(e);
+ m_cbBits ->setEnabled(e);
+ m_cbSign ->setEnabled(e);
+ m_cbChannels ->setEnabled(e);
+ m_cbEndianess ->setEnabled(e);
+ m_sbBufferSize->setEnabled(e);
+ m_pbUpCaptureURL ->setEnabled(up_possible);
+ m_pbDownCaptureURL->setEnabled(down_possible);
+}
+
+void StreamingConfiguration::slotSetDirty()
+{
+ m_dirty = true;
+}
+
+void StreamingConfiguration::slotUpdateSoundFormat()
+{
+ if (m_ignore_updates)
+ return;
+
+ slotSetDirty();
+ QListViewItem *playback_item = m_ListPlaybackURLs->selectedItem();
+ QListViewItem *capture_item = m_ListCaptureURLs->selectedItem();
+ if (playback_item) {
+ int idx = 0;
+ QListViewItem *i = m_ListPlaybackURLs->firstChild();
+ for (; i && i != playback_item; i = i->nextSibling()) {
+ ++idx;
+ }
+ getStreamOptions(m_PlaybackSoundFormats[idx], m_PlaybackBufferSizes[idx]);
+ }
+ else if (capture_item) {
+ int idx = 0;
+ QListViewItem *i = m_ListCaptureURLs->firstChild();
+ for (; i && i != capture_item; i = i->nextSibling()) {
+ ++idx;
+ }
+ getStreamOptions(m_CaptureSoundFormats[idx], m_CaptureBufferSizes[idx]);
+ }
+}
+
+
+void StreamingConfiguration::setStreamOptions(const SoundFormat &sf, int BufferSize)
+{
+ m_ignore_updates = true;
+
+ int idx_Format = FORMAT_RAW_IDX;
+ int idx_Rate = RATE_44100_IDX;
+ int idx_Bits = BITS_16_IDX;
+ int idx_Sign = SIGN_SIGNED_IDX;
+ int idx_Channels = CHANNELS_STEREO_IDX;
+ int idx_Endianess = ENDIAN_LITTLE_IDX;
+
+ if (sf.m_Encoding == "raw") {
+ idx_Format = FORMAT_RAW_IDX;
+ }
+ else {
+ // ...
+ }
+
+ switch(sf.m_SampleRate) {
+ case 48000 : idx_Rate = RATE_48000_IDX; break;
+ case 44100 : idx_Rate = RATE_44100_IDX; break;
+ case 22050 : idx_Rate = RATE_22050_IDX; break;
+ case 11025 : idx_Rate = RATE_11025_IDX; break;
+ }
+
+ switch(sf.m_SampleBits) {
+ case 8 : idx_Bits = BITS_8_IDX; break;
+ case 16 : idx_Bits = BITS_16_IDX; break;
+ }
+
+ switch(sf.m_IsSigned) {
+ case true : idx_Sign = SIGN_SIGNED_IDX; break;
+ case false : idx_Sign = SIGN_UNSIGNED_IDX; break;
+ }
+
+ switch(sf.m_Channels) {
+ case 2: idx_Channels = CHANNELS_STEREO_IDX; break;
+ case 1: idx_Channels = CHANNELS_MONO_IDX; break;
+ }
+
+ switch(sf.m_Endianess) {
+ case LITTLE_ENDIAN: idx_Endianess = ENDIAN_LITTLE_IDX; break;
+ case BIG_ENDIAN: idx_Endianess = ENDIAN_BIG_IDX; break;
+ }
+
+ m_cbFormat ->setCurrentItem(idx_Format);
+ m_cbRate ->setCurrentItem(idx_Rate);
+ m_cbBits ->setCurrentItem(idx_Bits);
+ m_cbSign ->setCurrentItem(idx_Sign);
+ m_cbChannels ->setCurrentItem(idx_Channels);
+ m_cbEndianess ->setCurrentItem(idx_Endianess);
+ m_sbBufferSize->setValue(BufferSize / 1024);
+
+ m_ignore_updates = false;
+}
+
+
+void StreamingConfiguration::getStreamOptions(SoundFormat &sf, int &BufferSize) const
+{
+ int idx_Format = m_cbFormat ->currentItem();
+ int idx_Rate = m_cbRate ->currentItem();
+ int idx_Bits = m_cbBits ->currentItem();
+ int idx_Sign = m_cbSign ->currentItem();
+ int idx_Channels = m_cbChannels ->currentItem();
+ int idx_Endianess = m_cbEndianess ->currentItem();
+
+ BufferSize = m_sbBufferSize->value() * 1024;
+
+ if (idx_Format == FORMAT_RAW_IDX) {
+ sf.m_Encoding = "raw";
+ }
+ else {
+ // ...
+ }
+
+ switch(idx_Rate) {
+ case RATE_48000_IDX : sf.m_SampleRate = 48000; break;
+ case RATE_44100_IDX : sf.m_SampleRate = 44100; break;
+ case RATE_22050_IDX : sf.m_SampleRate = 22050; break;
+ case RATE_11025_IDX : sf.m_SampleRate = 11025; break;
+ default : sf.m_SampleRate = 44100; break;
+ }
+
+ switch(idx_Bits) {
+ case BITS_8_IDX : sf.m_SampleBits = 8; break;
+ case BITS_16_IDX : sf.m_SampleBits = 16; break;
+ default : sf.m_SampleBits = 16; break;
+ }
+
+ switch(idx_Sign) {
+ case SIGN_SIGNED_IDX : sf.m_IsSigned = true; break;
+ case SIGN_UNSIGNED_IDX : sf.m_IsSigned = false; break;
+ default : sf.m_IsSigned = true; break;
+ }
+
+ switch(idx_Channels) {
+ case CHANNELS_STEREO_IDX : sf.m_Channels = 2; break;
+ case CHANNELS_MONO_IDX : sf.m_Channels = 1; break;
+ default : sf.m_Channels = 2; break;
+ }
+
+ switch(idx_Endianess) {
+ case ENDIAN_LITTLE_IDX : sf.m_Endianess = LITTLE_ENDIAN; break;
+ case ENDIAN_BIG_IDX : sf.m_Endianess = BIG_ENDIAN; break;
+ default : sf.m_Endianess = BYTE_ORDER; break;
+ }
+}
+
+#include "streaming-configuration.moc"
diff --git a/kradio3/plugins/streaming/streaming-configuration.h b/kradio3/plugins/streaming/streaming-configuration.h
new file mode 100644
index 0000000..f40a0cb
--- /dev/null
+++ b/kradio3/plugins/streaming/streaming-configuration.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ oss-sound-configuration.h - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_STREAMING_CONFIGURATION_H
+#define KRADIO_STREAMING_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "streaming-configuration-ui.h"
+#include "streaming.h"
+
+
+
+#define RATE_48000_IDX 0
+#define RATE_44100_IDX 1
+#define RATE_22050_IDX 2
+#define RATE_11025_IDX 3
+
+#define CHANNELS_STEREO_IDX 0
+#define CHANNELS_MONO_IDX 1
+
+#define SIGN_SIGNED_IDX 0
+#define SIGN_UNSIGNED_IDX 1
+
+#define BITS_16_IDX 0
+#define BITS_8_IDX 1
+
+#define ENDIAN_LITTLE_IDX 0
+#define ENDIAN_BIG_IDX 1
+
+#define FORMAT_RAW_IDX 0
+
+
+class StreamingConfiguration : public StreamingConfigurationUI
+{
+Q_OBJECT
+public :
+ StreamingConfiguration (QWidget *parent, StreamingDevice *streamer);
+ ~StreamingConfiguration ();
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+
+ void slotUpdateConfig();
+
+
+
+ void slotNewPlaybackChannel();
+ void slotDeletePlaybackChannel();
+ void slotUpPlaybackChannel();
+ void slotDownPlaybackChannel();
+
+ void slotNewCaptureChannel();
+ void slotDeleteCaptureChannel();
+ void slotUpCaptureChannel();
+ void slotDownCaptureChannel();
+
+ void slotPlaybackSelectionChanged();
+ void slotCaptureSelectionChanged();
+
+ void slotUpdateSoundFormat();
+ void slotSetDirty();
+
+protected:
+
+ void setStreamOptions(const SoundFormat &sf, int BufferSize);
+ void getStreamOptions(SoundFormat &sf, int &BufferSize) const ;
+
+
+ QValueList<SoundFormat> m_PlaybackSoundFormats, m_CaptureSoundFormats;
+ QValueList<int> m_PlaybackBufferSizes, m_CaptureBufferSizes;
+
+ bool m_ignore_updates;
+ bool m_dirty;
+ StreamingDevice *m_StreamingDevice;
+
+};
+
+#endif
diff --git a/kradio3/plugins/streaming/streaming-job.cpp b/kradio3/plugins/streaming/streaming-job.cpp
new file mode 100644
index 0000000..0c3736a
--- /dev/null
+++ b/kradio3/plugins/streaming/streaming-job.cpp
@@ -0,0 +1,279 @@
+/***************************************************************************
+ streaming-job.cpp - description
+ -------------------
+ begin : Sun Sept 3 2006
+ copyright : (C) 2006 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 "streaming-job.h"
+
+#include "../../src/include/utils.h"
+#include <kurl.h>
+
+#include <kio/job.h>
+
+
+StreamingJob::StreamingJob()
+ : QObject(),
+ m_URL(QString::null),
+ m_SoundFormat(),
+ m_BufferSize(65536),
+ m_Buffer(m_BufferSize),
+ m_OpenCounter(0),
+ m_StreamPos(0),
+ m_StartTime(0),
+ m_SkipCount(0),
+ m_KIO_Job(NULL),
+ m_capturing(false)
+{
+}
+
+StreamingJob::StreamingJob(const QString &_URL, const SoundFormat &_SoundFormat, size_t _bufferSize)
+ : QObject(),
+ m_URL(_URL),
+ m_SoundFormat(_SoundFormat),
+ m_BufferSize(_bufferSize),
+ m_Buffer(m_BufferSize),
+ m_OpenCounter(0),
+ m_StreamPos(0),
+ m_StartTime(0),
+ m_SkipCount(0),
+ m_KIO_Job(NULL),
+ m_capturing(false)
+{
+}
+
+StreamingJob::StreamingJob(const StreamingJob &c)
+ : QObject(),
+ m_URL(c.m_URL),
+ m_SoundFormat(c.m_SoundFormat),
+ m_BufferSize(c.m_BufferSize),
+ m_Buffer(m_BufferSize),
+ m_OpenCounter(0),
+ m_StreamPos(0),
+ m_StartTime(0),
+ m_SkipCount(0),
+ m_KIO_Job(NULL),
+ m_capturing(c.m_capturing)
+{
+}
+
+StreamingJob::~StreamingJob()
+{
+}
+
+
+void StreamingJob::setURL(const QString &url)
+{
+ if (m_URL != url) {
+ m_URL = url;
+ delete m_KIO_Job;
+ m_KIO_Job = NULL;
+ if (!m_capturing) {
+ startPutJob();
+ } else {
+ startGetJob();
+ }
+ }
+}
+
+
+void StreamingJob::setSoundFormat(const SoundFormat &sf)
+{
+ m_SoundFormat = sf;
+}
+
+
+void StreamingJob::setBufferSize(size_t buffer_size)
+{
+ if (m_BufferSize != buffer_size) {
+ m_Buffer.clear();
+ m_Buffer.resize(m_BufferSize = buffer_size);
+ }
+}
+
+
+bool StreamingJob::startPutJob()
+{
+ m_KIO_Job = KIO::put(m_URL, -1, true, false, false);
+ if (!m_KIO_Job)
+ return false;
+ m_KIO_Job->setAsyncDataEnabled(true);
+ connect (m_KIO_Job, SIGNAL(dataReq(KIO::Job *job, QByteArray &data)),
+ this, SLOT(slotWriteData (KIO::Job *job, QByteArray &data)));
+ connect (m_KIO_Job, SIGNAL(result(KIO::Job *)),
+ this, SLOT(slotIOJobResult(KIO::Job *)));
+ return true;
+}
+
+
+bool StreamingJob::startPlayback()
+{
+ if (!m_OpenCounter) {
+ m_Buffer.clear();
+ m_OpenCounter = 1;
+ if (!startPutJob())
+ return false;
+ m_StartTime = time(NULL);
+ m_StreamPos = 0;
+ if (m_KIO_Job->error()) {
+ emit logStreamError(m_URL, m_KIO_Job->errorString());
+ }
+ return m_KIO_Job->error() == 0;
+ }
+ else {
+ return true;
+ }
+}
+
+bool StreamingJob::stopPlayback()
+{
+ if (m_OpenCounter) {
+ if (!--m_OpenCounter) {
+ delete m_KIO_Job;
+ m_KIO_Job = NULL;
+ }
+ }
+ return true;
+}
+
+
+bool StreamingJob::startGetJob()
+{
+ m_KIO_Job = KIO::get(m_URL, false, false);
+ if (!m_KIO_Job)
+ return false;
+ m_KIO_Job->setAsyncDataEnabled(true);
+ connect (m_KIO_Job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+ this, SLOT(slotReadData(KIO::Job *, const QByteArray &)));
+ connect (m_KIO_Job, SIGNAL(result(KIO::Job *)),
+ this, SLOT(slotIOJobResult(KIO::Job *)));
+ return true;
+}
+
+
+bool StreamingJob::startCapture(const SoundFormat &/*proposed_format*/,
+ SoundFormat &real_format,
+ bool /*force_format*/)
+{
+ if (!m_OpenCounter) {
+ m_capturing = true;
+ m_Buffer.clear();
+ if (!startGetJob())
+ return false;
+ m_StartTime = time(NULL);
+ m_StreamPos = 0;
+ if (m_KIO_Job->error()) {
+ emit logStreamError(m_URL, m_KIO_Job->errorString());
+ }
+ return m_KIO_Job->error() == 0;
+ }
+ ++m_OpenCounter;
+ real_format = m_SoundFormat;
+ return true;
+}
+
+
+bool StreamingJob::stopCapture()
+{
+ if (m_OpenCounter) {
+ if (!--m_OpenCounter) {
+ delete m_KIO_Job;
+ m_KIO_Job = NULL;
+ }
+ }
+ return true;
+}
+
+
+void StreamingJob::slotReadData (KIO::Job */*job*/, const QByteArray &data)
+{
+ size_t free = m_Buffer.getFreeSize();
+ if (free < data.size()) {
+ m_SkipCount += data.size() - free;
+ emit logStreamWarning(m_URL, i18n("skipped %1 bytes").arg(data.size() - free));
+ }
+ else {
+ free = data.size();
+ }
+
+ m_Buffer.addData(data.data(), free);
+ m_StreamPos += free;
+
+ if (m_Buffer.getFreeSize() < data.size()) {
+ m_KIO_Job->suspend();
+ }
+}
+
+
+void StreamingJob::slotWriteData (KIO::Job */*job*/, QByteArray &)
+{
+ size_t size = m_Buffer.getFillSize();
+ if (size) {
+ char *buf = new char [size];
+ size = m_Buffer.takeData(buf, size);
+ QByteArray data;
+ data.assign(buf, size);
+ m_KIO_Job->sendAsyncData(data);
+ m_StreamPos += size;
+ }
+ else {
+ // does a warning really make sense here?
+ //emit logStreamWarning(m_URL, i18n("buffer underrun"));
+ m_SkipCount++;
+ }
+}
+
+
+void StreamingJob::playData(const char *data, size_t size, size_t &consumed_size)
+{
+ size_t free = m_Buffer.getFreeSize();
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? free : min(consumed_size, free);
+ if (free > size) {
+ free = size;
+ }
+ m_Buffer.addData(data, free);
+}
+
+
+bool StreamingJob::hasRecordedData() const
+{
+ return m_Buffer.getFillSize() > m_Buffer.getSize() / 3;
+}
+
+
+void StreamingJob::lockData(const char *&data, size_t &size, SoundMetaData &meta_data)
+{
+ data = m_Buffer.getData(size);
+ time_t cur_time = time(NULL);
+ meta_data = SoundMetaData(m_StreamPos, cur_time - m_StartTime, cur_time, m_URL);
+}
+
+
+void StreamingJob::removeData(size_t size)
+{
+ m_Buffer.removeData(size);
+ if (m_Buffer.getFreeSize() > m_Buffer.getSize() / 2) {
+ m_KIO_Job->resume();
+ }
+}
+
+void StreamingJob::slotIOJobResult (KIO::Job *job)
+{
+ if (job && job->error()) {
+ emit logStreamError(m_URL, job->errorString());
+ }
+}
+
+#include "streaming-job.moc"
+
diff --git a/kradio3/plugins/streaming/streaming-job.h b/kradio3/plugins/streaming/streaming-job.h
new file mode 100644
index 0000000..b88c32a
--- /dev/null
+++ b/kradio3/plugins/streaming/streaming-job.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+ streaming-job.h - description
+ -------------------
+ begin : Sun Sept 3 2006
+ copyright : (C) 2006 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KRADIO_STREAMING_JOB_H
+#define _KRADIO_STREAMING_JOB_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/ringbuffer.h"
+#include "../../src/include/soundformat.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+#include <qobject.h>
+
+#include <kio/jobclasses.h>
+
+class StreamingJob : public QObject
+{
+Q_OBJECT
+public:
+ StreamingJob();
+ StreamingJob(const QString &_URL, const SoundFormat &_SoundFormat, size_t _bufferSize);
+ StreamingJob(const StreamingJob &c);
+
+ virtual ~StreamingJob();
+
+ const QString &getURL() const { return m_URL; }
+ const SoundFormat &getSoundFormat() const { return m_SoundFormat; }
+ int getBufferSize() const { return m_BufferSize; }
+
+ void setURL(const QString &);
+ void setSoundFormat(const SoundFormat &);
+ void setBufferSize(size_t buffer_size);
+
+ bool startPlayback();
+ bool stopPlayback();
+
+ bool startCapture(const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format);
+ bool stopCapture();
+
+
+ void playData(const char *data, size_t size, size_t &consumed_size);
+ bool hasRecordedData() const;
+ void lockData(const char *&data, size_t &size, SoundMetaData &meta_data);
+ void removeData(size_t);
+
+protected slots:
+
+ void slotReadData (KIO::Job *job, const QByteArray &data);
+ void slotWriteData (KIO::Job *job, QByteArray &data);
+ void slotIOJobResult (KIO::Job *job);
+
+signals:
+
+ void logStreamError(const KURL &url, const QString &s);
+ void logStreamWarning(const KURL &url, const QString &s);
+
+protected:
+
+ bool startGetJob();
+ bool startPutJob();
+
+
+ QString m_URL;
+ SoundFormat m_SoundFormat;
+
+ size_t m_BufferSize;
+ RingBuffer m_Buffer;
+
+ unsigned m_OpenCounter;
+ Q_UINT64 m_StreamPos;
+ time_t m_StartTime;
+
+ size_t m_SkipCount;
+
+ KIO::TransferJob *m_KIO_Job;
+ bool m_capturing;
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/streaming/streaming.cpp b/kradio3/plugins/streaming/streaming.cpp
new file mode 100644
index 0000000..5f5431c
--- /dev/null
+++ b/kradio3/plugins/streaming/streaming.cpp
@@ -0,0 +1,526 @@
+/***************************************************************************
+ streaming.cpp - description
+ -------------------
+ begin : Sun Sept 3 2006
+ copyright : (C) 2006 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 "streaming.h"
+
+#include "../../src/include/aboutwidget.h"
+#include "../../src/include/utils.h"
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kurl.h>
+#include <klocale.h>
+
+#include "streaming-job.h"
+#include "streaming-configuration.h"
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS(StreamingDevice, "kradio-streaming", i18n("Streaming Support"));
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+
+StreamingDevice::StreamingDevice(const QString &name)
+ : QObject(NULL, NULL),
+ PluginBase(name, i18n("KRadio Streaming Plugin"))
+{
+ m_CaptureChannels.setAutoDelete(true);
+ m_PlaybackChannels.setAutoDelete(true);
+}
+
+
+StreamingDevice::~StreamingDevice()
+{
+ resetPlaybackStreams();
+ resetCaptureStreams();
+}
+
+
+bool StreamingDevice::connectI(Interface *i)
+{
+ bool a = PluginBase::connectI(i);
+ bool b = ISoundStreamClient::connectI(i);
+ return a || b;
+}
+
+
+bool StreamingDevice::disconnectI(Interface *i)
+{
+ bool a = PluginBase::disconnectI(i);
+ bool b = ISoundStreamClient::disconnectI(i);
+ return a || b;
+}
+
+void StreamingDevice::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_sendReleasePlayback(this);
+ s->register4_sendReleaseCapture(this);
+ s->register4_sendStartPlayback(this);
+ s->register4_sendPausePlayback(this);
+ s->register4_sendStopPlayback(this);
+ s->register4_queryIsPlaybackRunning(this);
+ s->register4_sendStartCaptureWithFormat(this);
+ s->register4_sendStopCapture(this);
+ s->register4_queryIsCaptureRunning(this);
+ s->register4_notifySoundStreamClosed(this);
+ s->register4_notifySoundStreamRedirected(this);
+ s->register4_notifySoundStreamData(this);
+ s->register4_notifyReadyForPlaybackData(this);
+ }
+}
+
+// PluginBase
+
+void StreamingDevice::saveState (KConfig *c) const
+{
+ c->setGroup(QString("streaming-") + PluginBase::name());
+ c->writeEntry("soundstreamclient-id", m_SoundStreamClientID);
+
+ c->writeEntry("playback-channels", m_PlaybackChannelList.size());
+ for (unsigned int i = 0; i < m_PlaybackChannelList.size(); ++i) {
+ QString s = m_PlaybackChannelList[i];
+ const StreamingJob *j = m_PlaybackChannels[s];
+
+ const SoundFormat &sf = j->getSoundFormat();
+ KURL url = j->getURL();
+ size_t buffer_size = j->getBufferSize();
+
+ sf.saveConfig("playback-channel-" + QString::number(i), c);
+ c->writeEntry("playback-channel-" + QString::number(i) + "-url", url.url());
+ c->writeEntry("playback-channel-" + QString::number(i) + "-buffer-size", buffer_size);
+ }
+
+ c->writeEntry("capture-channels", m_CaptureChannelList.size());
+ for (unsigned int i = 0; i < m_CaptureChannelList.size(); ++i) {
+ QString s = m_CaptureChannelList[i];
+ const StreamingJob *j = m_CaptureChannels[s];
+
+ const SoundFormat &sf = j->getSoundFormat();
+ KURL url = j->getURL();
+ size_t buffer_size = j->getBufferSize();
+
+ sf.saveConfig("capture-channel-" + QString::number(i), c);
+ c->writeEntry("capture-channel-" + QString::number(i) + "-url", url.url());
+ c->writeEntry("capture-channel-" + QString::number(i) + "-buffer-size", buffer_size);
+ }
+}
+
+void StreamingDevice::restoreState (KConfig *c)
+{
+ c->setGroup(QString("streaming-") + PluginBase::name());
+ setSoundStreamClientID(c->readEntry("soundstreamclient-id", getSoundStreamClientID()));
+
+ resetPlaybackStreams(false);
+ resetCaptureStreams(false);
+
+ int n = c->readNumEntry("playback-channels", 0);
+ for (int i = 0; i < n; ++i) {
+ SoundFormat sf;
+ sf.restoreConfig("playback-channel-" + QString::number(i), c);
+ QString url = c->readEntry("playback-channel-" + QString::number(i) + "-url", QString::null);
+ size_t buffer_size = c->readNum64Entry("playback-channel-" + QString::number(i) + "-buffer-size", 32*1024);
+
+ if (!url.isNull()) {
+ addPlaybackStream(url, sf, buffer_size, i == n-1);
+ }
+ }
+
+ n = c->readNumEntry("capture-channels", 0);
+ for (int i = 0; i < n; ++i) {
+ SoundFormat sf;
+ sf.restoreConfig("capture-channel-" + QString::number(i), c);
+ QString url = c->readEntry("capture-channel-" + QString::number(i) + "-url", QString::null);
+ size_t buffer_size = c->readNum64Entry("capture-channel-" + QString::number(i) + "-buffer-size", 32*1024);
+
+ if (!url.isNull()) {
+ addCaptureStream(url, sf, buffer_size, i == n-1);
+ }
+ }
+
+ if (!m_CaptureChannelList.size()) {
+ addCaptureStream("/dev/video24", SoundFormat(48000, 2, 16, true, BYTE_ORDER, "raw"), 65536);
+ }
+
+ emit sigUpdateConfig();
+}
+
+
+ConfigPageInfo StreamingDevice::createConfigurationPage()
+{
+ StreamingConfiguration *conf = new StreamingConfiguration(NULL, this);
+ QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig()));
+ return ConfigPageInfo (conf,
+ i18n("Streaming"),
+ i18n("Streaming Device Options"),
+ "kradio_streaming");
+}
+
+
+AboutPageInfo StreamingDevice::createAboutPage()
+{
+ return AboutPageInfo();
+}
+
+
+
+bool StreamingDevice::preparePlayback(SoundStreamID id, const QString &channel, bool /*active_mode*/, bool start_immediately)
+{
+ if (id.isValid() && m_PlaybackChannels.find(channel)) {
+ m_AllPlaybackStreams.insert(id, channel);
+ if (start_immediately)
+ startPlayback(id);
+ return true;
+ }
+ return false;
+}
+
+
+bool StreamingDevice::prepareCapture(SoundStreamID id, const QString &channel)
+{
+ logDebug("StreamingDevice::prepareCapture");
+ if (id.isValid() && m_CaptureChannels.find(channel)) {
+ m_AllCaptureStreams.insert(id, channel);
+ return true;
+ }
+ return false;
+}
+
+bool StreamingDevice::releasePlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_AllPlaybackStreams.contains(id)) {
+ stopPlayback(id);
+ if (!m_EnabledPlaybackStreams.contains(id))
+ m_AllPlaybackStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool StreamingDevice::releaseCapture(SoundStreamID id)
+{
+ logDebug("StreamingDevice::releaseCapture");
+ if (id.isValid() && m_AllCaptureStreams.contains(id)) {
+ stopCapture(id);
+ if (!m_EnabledCaptureStreams.contains(id))
+ m_AllCaptureStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool StreamingDevice::supportsPlayback() const
+{
+ return m_PlaybackChannels.size() > 0;
+}
+
+
+bool StreamingDevice::supportsCapture() const
+{
+ return m_CaptureChannels.size() > 0;
+}
+
+
+bool StreamingDevice::startPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_AllPlaybackStreams.contains(id)) {
+ m_EnabledPlaybackStreams.insert(id, m_AllPlaybackStreams[id]);
+ StreamingJob &x = *m_PlaybackChannels.find(m_AllPlaybackStreams[id]);
+ x.startPlayback();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool StreamingDevice::pausePlayback(SoundStreamID /*id*/)
+{
+ //return stopPlayback(id);
+ return false;
+}
+
+
+bool StreamingDevice::stopPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_EnabledPlaybackStreams.contains(id)) {
+ StreamingJob &x = *m_PlaybackChannels.find(m_AllPlaybackStreams[id]);
+ if (x.stopPlayback()) {
+ m_EnabledPlaybackStreams.remove(id);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool StreamingDevice::isPlaybackRunning(SoundStreamID id, bool &b) const
+{
+ if (id.isValid() && m_EnabledPlaybackStreams.contains(id)) {
+ b = true;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool StreamingDevice::startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format)
+{
+ logDebug("StreamingDevice::startCaptureWithFormat");
+ if (id.isValid() && m_AllCaptureStreams.contains(id)) {
+ m_EnabledCaptureStreams.insert(id, m_AllCaptureStreams[id]);
+ StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]);
+ x.startCapture(proposed_format, real_format, force_format);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool StreamingDevice::stopCapture(SoundStreamID id)
+{
+ if (id.isValid() && m_EnabledCaptureStreams.contains(id)) {
+ StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]);
+ if (x.stopCapture()) {
+ m_EnabledCaptureStreams.remove(id);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool StreamingDevice::isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const
+{
+ if (id.isValid() && m_EnabledCaptureStreams.contains(id)) {
+ StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]);
+ sf = x.getSoundFormat();
+ b = true;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool StreamingDevice::noticeSoundStreamClosed(SoundStreamID id)
+{
+ bool found = (stopCapture(id) && releaseCapture(id)) ||
+ (stopPlayback(id) && releasePlayback(id));
+ return found;
+}
+
+
+bool StreamingDevice::noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID)
+{
+ bool found = false;
+ if (newID != oldID) {
+ if (m_AllPlaybackStreams.contains(oldID)) {
+ m_AllPlaybackStreams.insert(newID, m_AllPlaybackStreams[oldID]);
+ m_AllPlaybackStreams.remove(oldID);
+ found = true;
+ }
+ if (m_EnabledPlaybackStreams.contains(oldID)) {
+ m_EnabledPlaybackStreams.insert(newID, m_EnabledPlaybackStreams[oldID]);
+ m_EnabledPlaybackStreams.remove(oldID);
+ found = true;
+ }
+ if (m_AllCaptureStreams.contains(oldID)) {
+ m_AllCaptureStreams.insert(newID, m_AllCaptureStreams[oldID]);
+ m_AllCaptureStreams.remove(oldID);
+ found = true;
+ }
+ if (m_EnabledCaptureStreams.contains(oldID)) {
+ m_EnabledCaptureStreams.insert(newID, m_EnabledCaptureStreams[oldID]);
+ m_EnabledCaptureStreams.remove(oldID);
+ found = true;
+ }
+ }
+ return found;
+}
+
+
+bool StreamingDevice::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &/*format*/,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &/*md*/
+ )
+{
+ if (id.isValid() && m_EnabledPlaybackStreams.contains(id)) {
+ StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]);
+ x.playData(data, size, consumed_size);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool StreamingDevice::noticeReadyForPlaybackData(SoundStreamID id, size_t free_size)
+{
+ if (!id.isValid() || !m_AllCaptureStreams.contains(id))
+ return false;
+ StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]);
+
+ while (x.hasRecordedData() && free_size > 0) {
+ const char *buffer = NULL;
+ size_t size = SIZE_T_DONT_CARE;
+ size_t consumed_size = SIZE_T_DONT_CARE;
+ SoundMetaData meta_data(0,0,0, i18n("internal stream, not stored (%1)").arg(m_AllCaptureStreams[id]));
+ x.lockData(buffer, size, meta_data); // get pointer to data and meta-data content
+ if (size > free_size)
+ size = free_size;
+ notifySoundStreamData(id, x.getSoundFormat(), buffer, size, consumed_size, meta_data);
+ if (consumed_size == SIZE_T_DONT_CARE)
+ consumed_size = size;
+ x.removeData(consumed_size);
+ free_size -= consumed_size;
+ if (consumed_size < size) {
+ logWarning(i18n("StreamingDevice %1::notifySoundStreamData: Playback Clients skipped %2 bytes").arg(name()).arg(size-consumed_size));
+ break;
+ }
+ }
+ return true;
+}
+
+
+
+const QStringList &StreamingDevice::getPlaybackChannels() const
+{
+ return m_PlaybackChannelList;
+}
+
+
+const QStringList &StreamingDevice::getCaptureChannels() const
+{
+ return m_CaptureChannelList;
+}
+
+
+QString StreamingDevice::getSoundStreamClientDescription() const
+{
+ return i18n("Streaming Device %1").arg(PluginBase::name());
+}
+
+
+void StreamingDevice::logStreamError(const KURL &url, const QString &s)
+{
+ logError(i18n("Streaming Device %1, %2: %3").arg(name()).arg(url.url()).arg(s));
+}
+
+void StreamingDevice::logStreamWarning(const KURL &url, const QString &s)
+{
+ logWarning(i18n("Streaming Device %1, %2: %3").arg(name()).arg(url.url()).arg(s));
+}
+
+
+bool StreamingDevice::getPlaybackStreamOptions(const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const
+{
+ if (m_PlaybackChannels.find(channel)) {
+ const StreamingJob *j = m_PlaybackChannels[channel];
+ url = j->getURL();
+ sf = j->getSoundFormat();
+ buffer_size = j->getBufferSize();
+ return true;
+ }
+ return false;
+}
+
+
+bool StreamingDevice::getCaptureStreamOptions(const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const
+{
+ if (m_CaptureChannels.find(channel)) {
+ const StreamingJob *j = m_CaptureChannels[channel];
+ url = j->getURL();
+ sf = j->getSoundFormat();
+ buffer_size = j->getBufferSize();
+ return true;
+ }
+ return false;
+}
+
+void StreamingDevice::resetPlaybackStreams(bool notification_enabled)
+{
+ while (m_EnabledPlaybackStreams.begin() != m_EnabledPlaybackStreams.end()) {
+ sendStopPlayback(m_EnabledPlaybackStreams.begin().key());
+ }
+ while (m_AllPlaybackStreams.begin() != m_AllPlaybackStreams.end()) {
+ releasePlayback(m_AllPlaybackStreams.begin().key());
+ }
+ m_PlaybackChannelList.clear();
+ m_PlaybackChannels.clear();
+ if (notification_enabled) {
+ notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannelList);
+ }
+}
+
+
+void StreamingDevice::resetCaptureStreams(bool notification_enabled)
+{
+ while (m_EnabledCaptureStreams.begin() != m_EnabledCaptureStreams.end()) {
+ sendStopCapture(m_EnabledCaptureStreams.begin().key());
+ }
+ while (m_AllCaptureStreams.begin() != m_AllCaptureStreams.end()) {
+ releaseCapture(m_AllCaptureStreams.begin().key());
+ }
+ m_CaptureChannelList.clear();
+ m_CaptureChannels.clear();
+ if (notification_enabled) {
+ notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannelList);
+ }
+}
+
+
+void StreamingDevice::addPlaybackStream(const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled)
+{
+ StreamingJob *x = new StreamingJob(url, sf, buffer_size);
+ connect(x, SIGNAL(logStreamError(const KURL &, const QString &)),
+ this, SLOT (logStreamError(const KURL &, const QString &)));
+
+ m_PlaybackChannelList.append(url);
+ m_PlaybackChannels.insert(url, x);
+ if (notification_enabled) {
+ notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannelList);
+ }
+}
+
+
+void StreamingDevice::addCaptureStream (const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled)
+{
+ StreamingJob *x = new StreamingJob(url, sf, buffer_size);
+ connect(x, SIGNAL(logStreamError(const KURL &, const QString &)),
+ this, SLOT (logStreamError(const KURL &, const QString &)));
+
+ m_CaptureChannelList.append(url);
+ m_CaptureChannels.insert(url, x);
+ if (notification_enabled) {
+ notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannelList);
+ }
+}
+
+
+#include "streaming.moc"
diff --git a/kradio3/plugins/streaming/streaming.h b/kradio3/plugins/streaming/streaming.h
new file mode 100644
index 0000000..430ab7b
--- /dev/null
+++ b/kradio3/plugins/streaming/streaming.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ streaming.h - description
+ -------------------
+ begin : Sun Sept 3 2006
+ copyright : (C) 2006 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KRADIO_STREAMING_H
+#define _KRADIO_STREAMING_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/plugins.h"
+#include "../../src/include/soundformat.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+#include <qobject.h>
+#include <qdict.h>
+
+class StreamingJob;
+
+class StreamingDevice : public QObject,
+ public PluginBase,
+ public ISoundStreamClient
+{
+Q_OBJECT
+
+public:
+ StreamingDevice (const QString &name);
+ virtual ~StreamingDevice ();
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ bool getPlaybackStreamOptions(const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const;
+ bool getCaptureStreamOptions (const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const;
+
+ void resetPlaybackStreams(bool notification_enabled = true);
+ void resetCaptureStreams(bool notification_enabled = true);
+ void addPlaybackStream(const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled = true);
+ void addCaptureStream (const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled = true);
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual QString pluginClassName() const { return "StreamingDevice"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // ISoundStreamClient: direct device access
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+ bool preparePlayback(SoundStreamID id, const QString &channel, bool active_mode, bool start_immediately);
+ bool prepareCapture(SoundStreamID id, const QString &channel);
+ bool releasePlayback(SoundStreamID id);
+ bool releaseCapture(SoundStreamID id);
+
+ANSWERS:
+ bool supportsPlayback() const;
+ bool supportsCapture() const;
+
+ QString getSoundStreamClientDescription() const;
+
+ // ISoundStreamClient: mixer access
+
+protected:
+
+ANSWERS:
+ const QStringList &getPlaybackChannels() const;
+ const QStringList &getCaptureChannels() const;
+
+ // ISoundStreamClient: generic broadcasts
+
+RECEIVERS:
+ bool startPlayback(SoundStreamID id);
+ bool pausePlayback(SoundStreamID id);
+ bool stopPlayback(SoundStreamID id);
+ bool isPlaybackRunning(SoundStreamID id, bool &b) const;
+
+ bool startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format);
+ bool stopCapture(SoundStreamID id);
+ bool isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const;
+
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID);
+
+ bool noticeReadyForPlaybackData(SoundStreamID id, size_t size);
+
+ bool noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+ );
+
+public slots:
+
+ void logStreamError(const KURL &url, const QString &s);
+ void logStreamWarning(const KURL &url, const QString &s);
+
+signals:
+
+ void sigUpdateConfig();
+
+protected:
+
+ QStringList m_PlaybackChannelList,
+ m_CaptureChannelList;
+
+ QDict<StreamingJob>
+ m_PlaybackChannels,
+ m_CaptureChannels;
+
+ QMap<SoundStreamID, QString>
+ m_AllPlaybackStreams,
+ m_AllCaptureStreams,
+ m_EnabledPlaybackStreams,
+ m_EnabledCaptureStreams;
+};
+
+
+
+#endif
diff --git a/kradio3/plugins/timecontrol/Makefile.am b/kradio3/plugins/timecontrol/Makefile.am
new file mode 100644
index 0000000..0ac954f
--- /dev/null
+++ b/kradio3/plugins/timecontrol/Makefile.am
@@ -0,0 +1,17 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libtimecontrol.la
+libtimecontrol_la_SOURCES = timecontrol-configuration.cpp \
+ timecontrol-configuration-ui.ui timecontrol.cpp
+libtimecontrol_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+noinst_HEADERS = timecontrol-configuration.h timecontrol.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-timecontrol.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-timecontrol.pot
diff --git a/kradio3/plugins/timecontrol/icons/Makefile.am b/kradio3/plugins/timecontrol/icons/Makefile.am
new file mode 100644
index 0000000..b3f2583
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/Makefile.am
@@ -0,0 +1,2 @@
+icons_ICON = AUTO
+iconsdir = $(kde_datadir)/kradio/icons
diff --git a/kradio3/plugins/timecontrol/icons/hi16-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_kalarm.png
new file mode 100644
index 0000000..d87e1c4
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_kalarm.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi16-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_zzz.png
new file mode 100644
index 0000000..c7184d5
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_zzz.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi22-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_kalarm.png
new file mode 100644
index 0000000..874fa0a
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_kalarm.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi22-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_zzz.png
new file mode 100644
index 0000000..f2184dd
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_zzz.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi32-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_kalarm.png
new file mode 100644
index 0000000..5547387
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_kalarm.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi32-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_zzz.png
new file mode 100644
index 0000000..5ddb326
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_zzz.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi330-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi330-action-kradio_zzz.png
new file mode 100644
index 0000000..bb4b6e3
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi330-action-kradio_zzz.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi48-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_kalarm.png
new file mode 100644
index 0000000..c3b8dd5
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_kalarm.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/icons/hi48-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_zzz.png
new file mode 100644
index 0000000..d443b05
--- /dev/null
+++ b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_zzz.png
Binary files differ
diff --git a/kradio3/plugins/timecontrol/po/Makefile.am b/kradio3/plugins/timecontrol/po/Makefile.am
new file mode 100644
index 0000000..35fe6fd
--- /dev/null
+++ b/kradio3/plugins/timecontrol/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = kradio-timecontrol
+POFILES = AUTO
diff --git a/kradio3/plugins/timecontrol/po/de.po b/kradio3/plugins/timecontrol/po/de.po
new file mode 100644
index 0000000..71a84f6
--- /dev/null
+++ b/kradio3/plugins/timecontrol/po/de.po
@@ -0,0 +1,129 @@
+# translation of de.po to
+# translation of kradio-timecontrol.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-06 01:16+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file timecontrol-configuration-ui.ui line 32
+#: rc.cpp:3 rc.cpp:68 timecontrol-configuration-ui.cpp:189
+#, no-c-format
+msgid "sleep countdown"
+msgstr "Schlummermodus"
+
+#. i18n: file timecontrol-configuration-ui.ui line 40
+#: rc.cpp:6 rc.cpp:71 timecontrol-configuration-ui.cpp:190
+#, no-c-format
+msgid " min"
+msgstr " min"
+
+#. i18n: file timecontrol-configuration-ui.ui line 117
+#: rc.cpp:9 rc.cpp:74 timecontrol-configuration-ui.cpp:191 timecontrol.cpp:270
+#, no-c-format
+msgid "Alarms"
+msgstr "Wecker"
+
+#. i18n: file timecontrol-configuration-ui.ui line 180
+#: rc.cpp:14 rc.cpp:79 timecontrol-configuration-ui.cpp:194
+#, no-c-format
+msgid "Date"
+msgstr "Datum"
+
+#. i18n: file timecontrol-configuration-ui.ui line 203
+#: rc.cpp:17 rc.cpp:82 timecontrol-configuration-ui.cpp:195
+#, no-c-format
+msgid "Time"
+msgstr "Uhrzeit"
+
+#. i18n: file timecontrol-configuration-ui.ui line 226
+#: rc.cpp:20 rc.cpp:85 timecontrol-configuration-ui.cpp:196
+#, no-c-format
+msgid "Volume"
+msgstr "Lautstärke"
+
+#. i18n: file timecontrol-configuration-ui.ui line 234
+#: rc.cpp:23 rc.cpp:88 timecontrol-configuration-ui.cpp:197
+#, no-c-format
+msgid " %"
+msgstr " %"
+
+#. i18n: file timecontrol-configuration-ui.ui line 263
+#: rc.cpp:26 rc.cpp:91 timecontrol-configuration-ui.cpp:198
+#, no-c-format
+msgid "enabled"
+msgstr "aktiv"
+
+#. i18n: file timecontrol-configuration-ui.ui line 331
+#: rc.cpp:50 rc.cpp:115 timecontrol-configuration-ui.cpp:207
+#, no-c-format
+msgid "daily"
+msgstr "täglich"
+
+#. i18n: file timecontrol-configuration-ui.ui line 341
+#: rc.cpp:53 rc.cpp:118 timecontrol-configuration-ui.cpp:208
+#, no-c-format
+msgid "Radio Station"
+msgstr "Sender"
+
+#. i18n: file timecontrol-configuration-ui.ui line 393
+#: rc.cpp:56 rc.cpp:121 timecontrol-configuration-ui.cpp:210
+#, no-c-format
+msgid "Start Playing"
+msgstr "Radio einschalten"
+
+#. i18n: file timecontrol-configuration-ui.ui line 401
+#: rc.cpp:59 rc.cpp:124 timecontrol-configuration-ui.cpp:211
+#, no-c-format
+msgid "Stop Playing"
+msgstr "Radio ausschalten"
+
+#. i18n: file timecontrol-configuration-ui.ui line 409
+#: rc.cpp:62 rc.cpp:127 timecontrol-configuration-ui.cpp:212
+#, no-c-format
+msgid "Start Recording"
+msgstr "Aufnahme starten"
+
+#. i18n: file timecontrol-configuration-ui.ui line 417
+#: rc.cpp:65 rc.cpp:130 timecontrol-configuration-ui.cpp:213
+#, no-c-format
+msgid "Stop Recording"
+msgstr "Aufnahme beenden"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: timecontrol-configuration.cpp:181
+msgid "<don't change>"
+msgstr "<nicht verändern>"
+
+#: timecontrol.cpp:42
+msgid "Time Control and Alarm Functions"
+msgstr "Zeitsteurungs- und Weckfunktionen"
+
+#: timecontrol.cpp:48
+msgid "TimeControl Plugin"
+msgstr "Zeitsteuerungs-Plugin"
+
+#: timecontrol.cpp:270
+msgid "Setup Alarms"
+msgstr "Wecker einrichten"
diff --git a/kradio3/plugins/timecontrol/po/ru.po b/kradio3/plugins/timecontrol/po/ru.po
new file mode 100644
index 0000000..6f95f37
--- /dev/null
+++ b/kradio3/plugins/timecontrol/po/ru.po
@@ -0,0 +1,129 @@
+# translation of ru.po to
+# translation of kradio-timecontrol.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-08 12:57+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file timecontrol-configuration-ui.ui line 32
+#: rc.cpp:3 rc.cpp:68 timecontrol-configuration-ui.cpp:189
+#, no-c-format
+msgid "sleep countdown"
+msgstr "Период таймера отключения"
+
+#. i18n: file timecontrol-configuration-ui.ui line 40
+#: rc.cpp:6 rc.cpp:71 timecontrol-configuration-ui.cpp:190
+#, no-c-format
+msgid " min"
+msgstr " мин"
+
+#. i18n: file timecontrol-configuration-ui.ui line 117
+#: rc.cpp:9 rc.cpp:74 timecontrol-configuration-ui.cpp:191 timecontrol.cpp:270
+#, no-c-format
+msgid "Alarms"
+msgstr "Расписание"
+
+#. i18n: file timecontrol-configuration-ui.ui line 180
+#: rc.cpp:14 rc.cpp:79 timecontrol-configuration-ui.cpp:194
+#, no-c-format
+msgid "Date"
+msgstr "Дата"
+
+#. i18n: file timecontrol-configuration-ui.ui line 203
+#: rc.cpp:17 rc.cpp:82 timecontrol-configuration-ui.cpp:195
+#, no-c-format
+msgid "Time"
+msgstr "Время"
+
+#. i18n: file timecontrol-configuration-ui.ui line 226
+#: rc.cpp:20 rc.cpp:85 timecontrol-configuration-ui.cpp:196
+#, no-c-format
+msgid "Volume"
+msgstr "Громкость"
+
+#. i18n: file timecontrol-configuration-ui.ui line 234
+#: rc.cpp:23 rc.cpp:88 timecontrol-configuration-ui.cpp:197
+#, no-c-format
+msgid " %"
+msgstr " %"
+
+#. i18n: file timecontrol-configuration-ui.ui line 263
+#: rc.cpp:26 rc.cpp:91 timecontrol-configuration-ui.cpp:198
+#, no-c-format
+msgid "enabled"
+msgstr "Включено"
+
+#. i18n: file timecontrol-configuration-ui.ui line 331
+#: rc.cpp:50 rc.cpp:115 timecontrol-configuration-ui.cpp:207
+#, no-c-format
+msgid "daily"
+msgstr "Ежедневно"
+
+#. i18n: file timecontrol-configuration-ui.ui line 341
+#: rc.cpp:53 rc.cpp:118 timecontrol-configuration-ui.cpp:208
+#, no-c-format
+msgid "Radio Station"
+msgstr "Радиостанция"
+
+#. i18n: file timecontrol-configuration-ui.ui line 393
+#: rc.cpp:56 rc.cpp:121 timecontrol-configuration-ui.cpp:210
+#, no-c-format
+msgid "Start Playing"
+msgstr "Начать воспроизведение"
+
+#. i18n: file timecontrol-configuration-ui.ui line 401
+#: rc.cpp:59 rc.cpp:124 timecontrol-configuration-ui.cpp:211
+#, no-c-format
+msgid "Stop Playing"
+msgstr "Остановить воспроизведение"
+
+#. i18n: file timecontrol-configuration-ui.ui line 409
+#: rc.cpp:62 rc.cpp:127 timecontrol-configuration-ui.cpp:212
+#, no-c-format
+msgid "Start Recording"
+msgstr "Начать запись"
+
+#. i18n: file timecontrol-configuration-ui.ui line 417
+#: rc.cpp:65 rc.cpp:130 timecontrol-configuration-ui.cpp:213
+#, no-c-format
+msgid "Stop Recording"
+msgstr "Остановить запись"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: timecontrol-configuration.cpp:181
+msgid "<don't change>"
+msgstr "<не менять>"
+
+#: timecontrol.cpp:42
+msgid "Time Control and Alarm Functions"
+msgstr "Функции таймера и работы по расписанию"
+
+#: timecontrol.cpp:48
+msgid "TimeControl Plugin"
+msgstr "Модуль ремени"
+
+#: timecontrol.cpp:270
+msgid "Setup Alarms"
+msgstr "Расписание"
diff --git a/kradio3/plugins/timecontrol/timecontrol-configuration-ui.ui b/kradio3/plugins/timecontrol/timecontrol-configuration-ui.ui
new file mode 100644
index 0000000..8b2b768
--- /dev/null
+++ b/kradio3/plugins/timecontrol/timecontrol-configuration-ui.ui
@@ -0,0 +1,452 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>TimeControlConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TimeControlConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>374</width>
+ <height>261</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelSleep</cstring>
+ </property>
+ <property name="text">
+ <string>sleep countdown</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>editSleep</cstring>
+ </property>
+ <property name="suffix">
+ <string> min</string>
+ </property>
+ <property name="maxValue">
+ <number>200</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="lineStep">
+ <number>5</number>
+ </property>
+ <property name="value">
+ <number>30</number>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="Line" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelAlarmList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Alarms</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonAlarmNew</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"filenew2"</iconset>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonDeleteAlarm</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"editdelete"</iconset>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>listAlarms</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout28</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout27</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelAlarmDate</cstring>
+ </property>
+ <property name="text">
+ <string>Date</string>
+ </property>
+ </widget>
+ <widget class="QDateEdit">
+ <property name="name">
+ <cstring>editAlarmDate</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout28</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelAlarmTime</cstring>
+ </property>
+ <property name="text">
+ <string>Time</string>
+ </property>
+ </widget>
+ <widget class="QTimeEdit">
+ <property name="name">
+ <cstring>editAlarmTime</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout29</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelAlarmVolume</cstring>
+ </property>
+ <property name="text">
+ <string>Volume</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>editAlarmVolume</cstring>
+ </property>
+ <property name="suffix">
+ <string> %</string>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ <property name="value">
+ <number>-1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>checkboxAlarmEnable</cstring>
+ </property>
+ <property name="text">
+ <string>enabled</string>
+ </property>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>100</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KListBox" row="0" column="1" rowspan="3" colspan="1">
+ <item>
+ <property name="text">
+ <string>Monday</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Tuesday</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Wednesday</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Thursday</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Friday</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Saturday</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Sunday</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>listWeekdays</cstring>
+ </property>
+ <property name="selectionMode">
+ <enum>Multi</enum>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>checkboxAlarmDaily</cstring>
+ </property>
+ <property name="text">
+ <string>daily</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelStationSelection</cstring>
+ </property>
+ <property name="text">
+ <string>Radio Station</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>comboStationSelection</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>pixmapAlarmStation</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>150</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QComboBox">
+ <item>
+ <property name="text">
+ <string>Start Playing</string>
+ </property>
+ <property name="pixmap">
+ <pixmap>"kradio_muteoff"</pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Stop Playing</string>
+ </property>
+ <property name="pixmap">
+ <pixmap>"kradio_muteon"</pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Start Recording</string>
+ </property>
+ <property name="pixmap">
+ <pixmap>"kradio_record"</pixmap>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Stop Recording</string>
+ </property>
+ <property name="pixmap">
+ <pixmap>"kradio_muteon"</pixmap>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>comboAlarmType</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>listAlarms</tabstop>
+ <tabstop>buttonAlarmNew</tabstop>
+ <tabstop>buttonDeleteAlarm</tabstop>
+ <tabstop>editAlarmDate</tabstop>
+ <tabstop>editAlarmTime</tabstop>
+ <tabstop>editAlarmVolume</tabstop>
+ <tabstop>checkboxAlarmDaily</tabstop>
+ <tabstop>checkboxAlarmEnable</tabstop>
+ <tabstop>comboStationSelection</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+</includes>
+<pixmapfunction>SmallIcon</pixmapfunction>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>klistbox.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/timecontrol/timecontrol-configuration.cpp b/kradio3/plugins/timecontrol/timecontrol-configuration.cpp
new file mode 100644
index 0000000..4ea6bce
--- /dev/null
+++ b/kradio3/plugins/timecontrol/timecontrol-configuration.cpp
@@ -0,0 +1,425 @@
+/***************************************************************************
+ timecontrol-configuration.cpp - description
+ -------------------
+ begin : Sam Aug 2 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 <math.h>
+#include <algorithm>
+using std::sort;
+
+#include <qdatetime.h>
+#include <qlistbox.h>
+#include <qcombobox.h>
+#include <qdatetimeedit.h>
+#include <qlabel.h>
+#include <qspinbox.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+
+#include <klistbox.h>
+#include <klocale.h>
+
+#include "../../src/include/stationlist.h"
+#include "../../src/include/alarm.h"
+#include "../../src/include/errorlog-interfaces.h"
+#include "../../src/include/radiostation.h"
+
+#include "timecontrol-configuration.h"
+
+class DateTimeCmp
+{
+public:
+ bool operator() (const Alarm &a, const Alarm &b) {
+ return a.nextAlarm(true) < b.nextAlarm(true);
+ }
+
+};
+
+TimeControlConfiguration::TimeControlConfiguration (QWidget *parent)
+ : TimeControlConfigurationUI(parent),
+ ITimeControlClient(),
+ IRadioClient(),
+ ignoreChanges(false),
+ m_dirty(false)
+{
+
+ QObject::connect(checkboxAlarmDaily, SIGNAL(toggled(bool)), this, SLOT(slotDailyChanged(bool)));
+ QObject::connect(listWeekdays, SIGNAL(highlighted(int)), this, SLOT(slotWeekdaysChanged()));
+ QObject::connect(checkboxAlarmEnable, SIGNAL(toggled(bool)), this, SLOT(slotEnabledChanged(bool)));
+ QObject::connect(comboStationSelection, SIGNAL(highlighted(int)), this, SLOT(slotStationChanged(int)));
+ QObject::connect(listAlarms, SIGNAL(highlighted(int)), this, SLOT(slotAlarmSelectChanged(int)));
+ QObject::connect(editAlarmDate, SIGNAL(valueChanged(const QDate &)), this, SLOT(slotDateChanged(const QDate &)));
+ QObject::connect(editAlarmTime, SIGNAL(valueChanged(const QTime &)), this, SLOT(slotTimeChanged(const QTime &)));
+ QObject::connect(editAlarmVolume, SIGNAL(valueChanged(int)), this, SLOT(slotVolumeChanged(int)));
+ QObject::connect(buttonAlarmNew, SIGNAL(clicked()), this, SLOT(slotNewAlarm()));
+ QObject::connect(buttonDeleteAlarm, SIGNAL(clicked()), this, SLOT(slotDeleteAlarm()));
+ QObject::connect(comboAlarmType, SIGNAL(highlighted(int)), this, SLOT(slotAlarmTypeChanged(int)));
+
+ QObject::connect(checkboxAlarmDaily, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+ QObject::connect(listWeekdays, SIGNAL(selectionChanged()), this, SLOT(slotSetDirty()));
+ QObject::connect(checkboxAlarmEnable, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty()));
+ QObject::connect(comboStationSelection, SIGNAL(activated(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(editAlarmDate, SIGNAL(valueChanged(const QDate &)), this, SLOT(slotSetDirty()));
+ QObject::connect(editAlarmTime, SIGNAL(valueChanged(const QTime &)), this, SLOT(slotSetDirty()));
+ QObject::connect(editAlarmVolume, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(buttonAlarmNew, SIGNAL(clicked()), this, SLOT(slotSetDirty()));
+ QObject::connect(buttonDeleteAlarm, SIGNAL(clicked()), this, SLOT(slotSetDirty()));
+ QObject::connect(comboAlarmType, SIGNAL(activated(int)), this, SLOT(slotSetDirty()));
+ QObject::connect(editSleep, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+}
+
+TimeControlConfiguration::~TimeControlConfiguration ()
+{
+}
+
+bool TimeControlConfiguration::connectI (Interface *i)
+{
+ bool a = ITimeControlClient::connectI(i);
+ bool b = IRadioClient::connectI(i);
+ return a || b;
+}
+
+
+bool TimeControlConfiguration::disconnectI (Interface *i)
+{
+ bool a = ITimeControlClient::disconnectI(i);
+ bool b = IRadioClient::disconnectI(i);
+ return a || b;
+}
+
+
+// ITimeControlClient
+
+bool TimeControlConfiguration::noticeAlarmsChanged(const AlarmVector &sl)
+{
+ int idx = listAlarms->currentItem();
+ int currentID = (idx >= 0 && (unsigned)idx < alarms.size()) ? alarms[idx].ID() : -1;
+
+ alarms = sl;
+ sort(alarms.begin(), alarms.end(), DateTimeCmp());
+
+ bool oldBlock = listAlarms->signalsBlocked();
+ listAlarms->blockSignals(true);
+
+ listAlarms->clear();
+ idx = -1;
+ int k = 0;
+ for (ciAlarmVector i = alarms.begin(); i != alarms.end(); ++i, ++k) {
+ listAlarms->insertItem(i->nextAlarm(true).toString());
+ if (i->ID() == currentID)
+ idx = k;
+ }
+ listAlarms->setCurrentItem(idx);
+
+ listAlarms->blockSignals(oldBlock);
+
+ slotAlarmSelectChanged(idx);
+ return true;
+}
+
+bool TimeControlConfiguration::noticeAlarm(const Alarm &)
+{
+ return false;
+}
+
+bool TimeControlConfiguration::noticeNextAlarmChanged(const Alarm *)
+{
+ noticeAlarmsChanged(alarms);
+ return true;
+}
+
+bool TimeControlConfiguration::noticeCountdownStarted(const QDateTime &/*end*/)
+{
+ return false;
+}
+
+bool TimeControlConfiguration::noticeCountdownStopped()
+{
+ return false;
+}
+
+bool TimeControlConfiguration::noticeCountdownZero()
+{
+ return false;
+}
+
+bool TimeControlConfiguration::noticeCountdownSecondsChanged(int n)
+{
+ editSleep->setValue((int)rint(n / 60));
+ return false;
+}
+
+
+// IRadioClient
+
+bool TimeControlConfiguration::noticePowerChanged(bool /*on*/)
+{
+ return false;
+}
+
+bool TimeControlConfiguration::noticeStationChanged (const RadioStation &, int /*idx*/)
+{
+ return false;
+}
+
+bool TimeControlConfiguration::noticeStationsChanged(const StationList &sl)
+{
+ comboStationSelection->clear();
+ stationIDs.clear();
+ comboStationSelection->insertItem(i18n("<don't change>"));
+ stationIDs.push_back(QString::null);
+
+ for (RawStationList::Iterator i(sl.all()); i.current(); ++i) {
+ comboStationSelection->insertItem(i.current()->iconName(),
+ i.current()->longName());
+ stationIDs.push_back(i.current()->stationID());
+ }
+ return true;
+}
+
+
+// Slots
+
+
+void TimeControlConfiguration::slotDateChanged( const QDate &d )
+{
+ if (ignoreChanges) return;
+
+ int idx = listAlarms->currentItem();
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ Alarm &a = alarms[idx];
+ a.setDate(d);
+
+ ignoreChanges = true;
+ bool oldBlock = listAlarms->signalsBlocked();
+ listAlarms->blockSignals(true);
+ noticeAlarmsChanged(alarms);
+ listAlarms->blockSignals(oldBlock);
+ ignoreChanges = false;
+ }
+}
+
+
+void TimeControlConfiguration::slotTimeChanged(const QTime &t)
+{
+ if (ignoreChanges) return;
+
+ int idx = listAlarms->currentItem();
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ Alarm &a = alarms[idx];
+ a.setTime(t);
+
+ ignoreChanges = true;
+ bool oldBlock = listAlarms->signalsBlocked();
+ listAlarms->blockSignals(true);
+ noticeAlarmsChanged(alarms);
+ listAlarms->blockSignals(oldBlock);
+ ignoreChanges = false;
+ }
+}
+
+
+void TimeControlConfiguration::slotDailyChanged (bool b)
+{
+ if (ignoreChanges) return;
+
+ int idx = listAlarms->currentItem();
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ Alarm &a = alarms[idx];
+ a.setDaily(b);
+
+ ignoreChanges = true;
+ bool oldBlock = listAlarms->signalsBlocked();
+ listAlarms->blockSignals(true);
+ noticeAlarmsChanged(alarms);
+ listAlarms->blockSignals(oldBlock);
+ ignoreChanges = false;
+
+ editAlarmDate ->setDisabled(b);
+ labelAlarmDate->setDisabled(b);
+ listWeekdays ->setDisabled(!b);
+ }
+}
+
+
+void TimeControlConfiguration::slotWeekdaysChanged ()
+{
+ if (ignoreChanges) return;
+
+ int mask = 0;
+ for (int i = 0; i < 7; ++i) {
+ if (listWeekdays->isSelected(i)) {
+ mask |= (1 << i);
+ }
+ }
+
+ int idx = listAlarms->currentItem();
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ Alarm &a = alarms[idx];
+ a.setWeekdayMask(mask);
+
+ ignoreChanges = true;
+ bool oldBlock = listAlarms->signalsBlocked();
+ listAlarms->blockSignals(true);
+ noticeAlarmsChanged(alarms);
+ listAlarms->blockSignals(oldBlock);
+ ignoreChanges = false;
+ }
+}
+
+
+void TimeControlConfiguration::slotEnabledChanged( bool b)
+{
+ int idx = listAlarms->currentItem();
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ alarms[idx].setEnabled(b);
+ }
+}
+
+
+void TimeControlConfiguration::slotStationChanged( int i )
+{
+ int idx = listAlarms->currentItem();
+ if ( idx >= 0 && (unsigned)idx < alarms.size()
+ && i >= 0 && (unsigned)i < stationIDs.size())
+ {
+ alarms[idx].setStationID( stationIDs[i] );
+ }
+}
+
+
+void TimeControlConfiguration::slotVolumeChanged( int v )
+{
+ int idx = listAlarms->currentItem();
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ alarms[idx].setVolumePreset(0.01 * (float)v);
+ }
+}
+
+
+void TimeControlConfiguration::slotAlarmTypeChanged(int t)
+{
+ int idx = listAlarms->currentItem();
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ alarms[idx].setAlarmType((Alarm::AlarmType)t);
+ }
+}
+
+
+void TimeControlConfiguration::slotAlarmSelectChanged(int idx)
+{
+ if (ignoreChanges) return;
+ ignoreChanges = true;
+
+ Alarm a;
+ bool valid = false;
+
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+
+ a = alarms[idx];
+ valid = true;
+
+ }
+
+ editAlarmDate ->setDisabled(!valid || a.isDaily());
+ labelAlarmDate ->setDisabled(!valid || a.isDaily());
+ listWeekdays ->setDisabled(!valid ||!a.isDaily());
+ editAlarmTime ->setDisabled(!valid);
+ labelAlarmTime ->setDisabled(!valid);
+ labelAlarmVolume ->setDisabled(!valid);
+ editAlarmVolume ->setDisabled(!valid);
+ checkboxAlarmDaily ->setDisabled(!valid);
+ checkboxAlarmEnable ->setDisabled(!valid);
+ comboStationSelection->setDisabled(!valid);
+ labelStationSelection->setDisabled(!valid);
+ buttonDeleteAlarm ->setDisabled(!valid);
+ comboAlarmType ->setDisabled(!valid);
+
+ editAlarmDate ->setDate(a.alarmTime().date());
+ editAlarmTime ->setTime(a.alarmTime().time());
+ checkboxAlarmDaily ->setChecked(a.isDaily());
+ checkboxAlarmEnable ->setChecked(a.isEnabled());
+ editAlarmVolume ->setValue((int)rint(a.volumePreset() * 100));
+ comboAlarmType ->setCurrentItem(a.alarmType());
+
+ int k = 0;
+ const QString &sID = a.stationID();
+ for (int i = 0; !k && i < (int)stationIDs.size(); ++i)
+ if (stationIDs[i] == sID) k = i;
+ comboStationSelection->setCurrentItem(k);
+
+ int m = a.weekdayMask();
+ for (int i = 0; i < 7; ++i) {
+ listWeekdays->setSelected(i, m & (1 << i));
+ }
+
+ ignoreChanges = false;
+}
+
+
+void TimeControlConfiguration::slotNewAlarm()
+{
+ QDateTime dt(QDateTime::currentDateTime());
+ Alarm a(dt, false, false);
+ alarms.push_back(a);
+ listAlarms->insertItem(a.alarmTime().toString());
+ listAlarms->setSelected(listAlarms->count() - 1, true);
+ noticeAlarmsChanged(alarms);
+}
+
+
+void TimeControlConfiguration::slotDeleteAlarm()
+{
+ int idx = listAlarms->currentItem();
+
+ if (idx >= 0 && (unsigned)idx < alarms.size()) {
+ // unfortunately a function vector<>::erase(idx) does not exist
+ iAlarmVector i = alarms.begin();
+ for (int k = 0; k < idx; ++k)
+ ++i;
+ if (i != alarms.end())
+ alarms.erase(i);
+ listAlarms->removeItem(idx);
+ }
+}
+
+
+void TimeControlConfiguration::slotOK()
+{
+ if (m_dirty) {
+ sendAlarms(alarms);
+ sendCountdownSeconds(editSleep->value() * 60);
+ m_dirty = false;
+ }
+}
+
+void TimeControlConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ noticeAlarmsChanged(queryAlarms());
+ noticeCountdownSecondsChanged(queryCountdownSeconds());
+ m_dirty = false;
+ }
+}
+
+void TimeControlConfiguration::slotSetDirty()
+{
+ if (!ignoreChanges) {
+ m_dirty = true;
+ }
+}
+
+
+#include "timecontrol-configuration.moc"
diff --git a/kradio3/plugins/timecontrol/timecontrol-configuration.h b/kradio3/plugins/timecontrol/timecontrol-configuration.h
new file mode 100644
index 0000000..ac4570f
--- /dev/null
+++ b/kradio3/plugins/timecontrol/timecontrol-configuration.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ timecontro-configuration.h - description
+ -------------------
+ begin : Sam Aug 2 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. *
+ * *
+ ***************************************************************************/
+#ifndef KRADIO_TIMECONTROL_CONFIGURATION_H
+#define KRADIO_TIMECONTROL_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/radio_interfaces.h"
+#include "../../src/include/timecontrol_interfaces.h"
+#include "timecontrol-configuration-ui.h"
+
+class TimeControl;
+class QWidget;
+
+class TimeControlConfiguration : public TimeControlConfigurationUI,
+ public ITimeControlClient,
+ public IRadioClient
+{
+Q_OBJECT
+public :
+ TimeControlConfiguration (QWidget *parent);
+ ~TimeControlConfiguration ();
+
+ bool connectI (Interface *i);
+ bool disconnectI (Interface *i);
+
+// ITimeControlClient
+
+ bool noticeAlarmsChanged(const AlarmVector &sl);
+ bool noticeAlarm(const Alarm &);
+ bool noticeNextAlarmChanged(const Alarm *);
+ bool noticeCountdownStarted(const QDateTime &end);
+ bool noticeCountdownStopped();
+ bool noticeCountdownZero();
+ bool noticeCountdownSecondsChanged(int n);
+
+// IRadioClient
+
+ bool noticePowerChanged(bool on);
+ bool noticeStationChanged (const RadioStation &, int idx);
+ bool noticeStationsChanged(const StationList &sl);
+ bool noticePresetFileChanged(const QString &/*f*/) { return false; }
+
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; }
+
+protected slots:
+
+ void slotDailyChanged (bool daily);
+ void slotWeekdaysChanged ();
+ void slotEnabledChanged (bool enable);
+ void slotStationChanged (int idx);
+ void slotAlarmSelectChanged(int idx);
+ void slotDateChanged(const QDate &d);
+ void slotTimeChanged(const QTime &d);
+ void slotVolumeChanged(int v);
+ void slotAlarmTypeChanged(int idx);
+
+ void slotNewAlarm();
+ void slotDeleteAlarm();
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+protected:
+
+ AlarmVector alarms;
+ vector<QString> stationIDs;
+
+ bool ignoreChanges;
+ bool m_dirty;
+};
+
+#endif
diff --git a/kradio3/plugins/timecontrol/timecontrol.cpp b/kradio3/plugins/timecontrol/timecontrol.cpp
new file mode 100644
index 0000000..42441ac
--- /dev/null
+++ b/kradio3/plugins/timecontrol/timecontrol.cpp
@@ -0,0 +1,301 @@
+/***************************************************************************
+ timecontrol.cpp - description
+ -------------------
+ begin : Son Jan 12 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 <kaboutdata.h>
+#include <kconfig.h>
+
+#include "timecontrol.h"
+#include "timecontrol-configuration.h"
+#include "../../src/include/pluginmanager.h"
+#include "../../src/include/aboutwidget.h"
+
+//const char *AlarmListElement = "alarmlist";
+//const char *AlarmElement = "alarm";
+const char *AlarmDateElement = "date";
+const char *AlarmTimeElement = "time";
+const char *AlarmDailyElement = "daily";
+const char *AlarmWeekdayMaskElement = "weekdayMask";
+const char *AlarmEnabledElement = "enabled";
+const char *AlarmStationIDElement = "stationID";
+//const char *AlarmFrequencyElement = "frequency";
+const char *AlarmVolumeElement = "volume";
+const char *AlarmTypeElement = "type";
+
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS(TimeControl, "kradio-timecontrol", i18n("Time Control and Alarm Functions"));
+
+///////////////////////////////////////////////////////////////////////
+
+
+TimeControl::TimeControl (const QString &n)
+ : PluginBase(n, i18n("TimeControl Plugin")),
+ m_waitingFor(NULL),
+ m_countdownSeconds(0),
+ m_alarmTimer(this),
+ m_countdownTimer(this)
+{
+ QObject::connect(&m_alarmTimer, SIGNAL(timeout()), this, SLOT(slotQTimerAlarmTimeout()));
+ QObject::connect(&m_countdownTimer, SIGNAL(timeout()), this, SLOT(slotQTimerCountdownTimeout()));
+}
+
+
+TimeControl::~TimeControl ()
+{
+ m_waitingFor = NULL;
+}
+
+bool TimeControl::connectI (Interface *i)
+{
+ bool a = ITimeControl::connectI(i);
+ bool b = PluginBase::connectI(i);
+ return a || b;
+}
+
+bool TimeControl::disconnectI (Interface *i)
+{
+ bool a = ITimeControl::disconnectI(i);
+ bool b = PluginBase::disconnectI(i);
+ return a || b;
+}
+
+bool TimeControl::setAlarms (const AlarmVector &al)
+{
+ if (m_alarms != al) {
+ m_waitingFor = NULL;
+
+ m_alarms = al;
+
+ slotQTimerAlarmTimeout();
+
+ notifyAlarmsChanged(m_alarms);
+ }
+ return true;
+}
+
+
+bool TimeControl::setCountdownSeconds(int n)
+{
+ int old = m_countdownSeconds;
+ m_countdownSeconds = n;
+ if (old != n)
+ notifyCountdownSecondsChanged(n);
+ return true;
+}
+
+
+bool TimeControl::startCountdown()
+{
+ m_countdownEnd = QDateTime::currentDateTime().addSecs(m_countdownSeconds);
+ m_countdownTimer.start(m_countdownSeconds * 1000, true);
+
+ notifyCountdownStarted(getCountdownEnd());
+
+ return true;
+}
+
+
+bool TimeControl::stopCountdown()
+{
+ m_countdownTimer.stop();
+ m_countdownEnd = QDateTime();
+
+ notifyCountdownStopped();
+
+ return true;
+}
+
+
+QDateTime TimeControl::getNextAlarmTime() const
+{
+ const Alarm *a = getNextAlarm();
+ if (a)
+ return a->nextAlarm();
+ else
+ return QDateTime();
+}
+
+
+const Alarm *TimeControl::getNextAlarm () const
+{
+ QDateTime now = QDateTime::currentDateTime(),
+ next;
+
+ const Alarm *retval = NULL;
+
+ for (ciAlarmVector i = m_alarms.begin(); i != m_alarms.end(); ++i) {
+ QDateTime n = i->nextAlarm();
+ if (n.isValid() && n > now && ( ! next.isValid() || n < next)) {
+ next = n;
+ retval = &(*i);
+ }
+ }
+
+ QDateTime old = m_nextAlarm_tmp;
+ m_nextAlarm_tmp = next;
+ if (old != m_nextAlarm_tmp) {
+ notifyNextAlarmChanged(retval);
+ }
+
+ return retval;
+}
+
+
+QDateTime TimeControl::getCountdownEnd () const
+{
+ if (m_countdownTimer.isActive())
+ return m_countdownEnd;
+ else
+ return QDateTime();
+}
+
+
+void TimeControl::slotQTimerCountdownTimeout()
+{
+ stopCountdown();
+
+ notifyCountdownZero();
+}
+
+
+void TimeControl::slotQTimerAlarmTimeout()
+{
+ if (m_waitingFor) {
+ notifyAlarm(*m_waitingFor);
+ }
+
+ QDateTime now = QDateTime::currentDateTime();
+ Alarm const *n = getNextAlarm();
+ QDateTime na = getNextAlarmTime();
+
+ m_waitingFor = NULL;
+
+ if (na.isValid()) {
+
+ int days = now.daysTo(na);
+ int msecs = now.time().msecsTo(na.time());
+
+ if (days > 1) {
+ m_alarmTimer.start(24 * 3600 * 1000, true);
+
+ } else if (days >= 0) {
+
+ if (days > 0)
+ msecs += days * 24 * 3600 * 1000;
+
+ if (msecs > 0) {
+ m_waitingFor = n;
+ m_alarmTimer.start(msecs, true);
+ }
+ }
+ }
+}
+
+
+void TimeControl::restoreState (KConfig *config)
+{
+ AlarmVector al;
+
+ config->setGroup(QString("timecontrol-") + name());
+
+ int nAlarms = config->readNumEntry ("nAlarms", 0);
+ for (int idx = 1; idx <= nAlarms; ++idx) {
+
+ QString num = QString().setNum(idx);
+ QDateTime d = config->readDateTimeEntry(AlarmTimeElement + num);
+ bool enable = config->readBoolEntry(AlarmEnabledElement + num, false);
+ bool daily = config->readBoolEntry(AlarmDailyElement + num, false);
+ int weekdayMask = config->readNumEntry(AlarmWeekdayMaskElement + num, 0x7F);
+ float vol = config->readDoubleNumEntry(AlarmVolumeElement + num, 1);
+ QString sid = config->readEntry(AlarmStationIDElement + num, QString::null);
+ int type = config->readNumEntry(AlarmTypeElement + num, 0);
+
+ enable &= d.isValid();
+
+ Alarm a ( d, daily, enable);
+ a.setVolumePreset(vol);
+ a.setWeekdayMask(weekdayMask);
+ a.setStationID(sid);
+ a.setAlarmType((Alarm::AlarmType)type);
+ al.push_back(a);
+ }
+
+ setAlarms(al);
+ setCountdownSeconds(config->readNumEntry("countdownSeconds", 30*60));
+}
+
+
+void TimeControl::saveState (KConfig *config) const
+{
+ config->setGroup(QString("timecontrol-") + name());
+
+ config->writeEntry("nAlarms", m_alarms.size());
+ int idx = 1;
+ ciAlarmVector end = m_alarms.end();
+ for (ciAlarmVector i = m_alarms.begin(); i != end; ++i, ++idx) {
+ QString num = QString().setNum(idx);
+ config->writeEntry (AlarmTimeElement + num, i->alarmTime());
+ config->writeEntry (AlarmEnabledElement + num, i->isEnabled());
+ config->writeEntry (AlarmDailyElement + num, i->isDaily());
+ config->writeEntry (AlarmWeekdayMaskElement + num, i->weekdayMask());
+ config->writeEntry (AlarmVolumeElement + num, i->volumePreset());
+ config->writeEntry (AlarmStationIDElement + num, i->stationID());
+ config->writeEntry (AlarmTypeElement + num, i->alarmType());
+ }
+
+ config->writeEntry("countdownSeconds", m_countdownSeconds);
+}
+
+
+ConfigPageInfo TimeControl::createConfigurationPage()
+{
+ TimeControlConfiguration *conf = new TimeControlConfiguration(NULL);
+ connectI(conf);
+ return ConfigPageInfo (conf, i18n("Alarms"), i18n("Setup Alarms"), "kradio_kalarm");
+}
+
+
+AboutPageInfo TimeControl::createAboutPage()
+{
+/* KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("Time Control Plugin for KRadio."
+ "<P>"
+ "Provides Alarms and Sleep Countdown"
+ "<P>"),
+ 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("Alarms"),
+ i18n("Time Control Plugin"),
+ "kradio_kalarm"
+ );*/
+ return AboutPageInfo();
+}
+
+
+#include "timecontrol.moc"
diff --git a/kradio3/plugins/timecontrol/timecontrol.h b/kradio3/plugins/timecontrol/timecontrol.h
new file mode 100644
index 0000000..f38bae9
--- /dev/null
+++ b/kradio3/plugins/timecontrol/timecontrol.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ timecontrol.h - description
+ -------------------
+ begin : Son Jan 12 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_TIMECONTROL_H
+#define KRADIO_TIMECONTROL_H
+
+#include <qobject.h>
+#include <qtimer.h>
+
+#include "../../src/include/alarm.h"
+#include "../../src/include/plugins.h"
+#include "../../src/include/timecontrol_interfaces.h"
+
+// well, it has to be a QObject :( , but only for
+// receiving QTimer - timeouts
+
+class TimeControl : public QObject,
+ public PluginBase,
+ public ITimeControl
+{
+Q_OBJECT
+protected:
+ AlarmVector m_alarms;
+ Alarm const * m_waitingFor; // m_alarmTimer is exactly for this date/time
+
+ int m_countdownSeconds; // in seconds
+ QDateTime m_countdownEnd;
+
+ QTimer m_alarmTimer;
+ QTimer m_countdownTimer;
+
+ mutable QDateTime m_nextAlarm_tmp; // used to recognize nextAlarm changes
+
+public:
+ TimeControl (const QString &name);
+ ~TimeControl();
+
+ virtual QString pluginClassName() const { return "TimeControl"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ virtual bool connectI (Interface *i);
+ virtual bool disconnectI (Interface *i);
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+
+ // ITimeControl Interface methods
+
+RECEIVERS:
+ bool setAlarms(const AlarmVector &sl);
+ bool setCountdownSeconds(int n);
+ bool startCountdown();
+ bool stopCountdown();
+
+ANSWERS:
+ QDateTime getNextAlarmTime () const;
+ const Alarm* getNextAlarm () const;
+ const AlarmVector & getAlarms () const { return m_alarms; }
+ int getCountdownSeconds () const { return m_countdownSeconds; }
+ QDateTime getCountdownEnd () const;
+
+
+ // slots for receiving timeout messages of timers
+
+protected slots:
+ virtual void slotQTimerAlarmTimeout();
+ virtual void slotQTimerCountdownTimeout();
+
+};
+
+
+#endif
diff --git a/kradio3/plugins/timeshifter/Makefile.am b/kradio3/plugins/timeshifter/Makefile.am
new file mode 100644
index 0000000..23da794
--- /dev/null
+++ b/kradio3/plugins/timeshifter/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libtimeshifter.la
+libtimeshifter_la_SOURCES = timeshifter.cpp timeshifter-configuration-ui.ui \
+ timeshifter-configuration.cpp
+libtimeshifter_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = timeshifter.h timeshifter-configuration.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-timeshifter.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-timeshifter.pot
diff --git a/kradio3/plugins/timeshifter/icons/Makefile.am b/kradio3/plugins/timeshifter/icons/Makefile.am
new file mode 100644
index 0000000..b3f2583
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/Makefile.am
@@ -0,0 +1,2 @@
+icons_ICON = AUTO
+iconsdir = $(kde_datadir)/kradio/icons
diff --git a/kradio3/plugins/timeshifter/icons/hi16-action-kradio_pause.png b/kradio3/plugins/timeshifter/icons/hi16-action-kradio_pause.png
new file mode 100644
index 0000000..a5f47a7
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi16-action-kradio_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/icons/hi16-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi16-app-kradio_plus_pause.png
new file mode 100644
index 0000000..320ba48
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi16-app-kradio_plus_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/icons/hi22-action-kradio_pause.png b/kradio3/plugins/timeshifter/icons/hi22-action-kradio_pause.png
new file mode 100644
index 0000000..69dfb9e
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi22-action-kradio_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/icons/hi22-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi22-app-kradio_plus_pause.png
new file mode 100644
index 0000000..31a25ac
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi22-app-kradio_plus_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/icons/hi32-action-kradio_pause.png b/kradio3/plugins/timeshifter/icons/hi32-action-kradio_pause.png
new file mode 100644
index 0000000..8425c1c
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi32-action-kradio_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/icons/hi32-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi32-app-kradio_plus_pause.png
new file mode 100644
index 0000000..9b42662
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi32-app-kradio_plus_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/icons/hi48-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi48-app-kradio_plus_pause.png
new file mode 100644
index 0000000..efaa1e1
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi48-app-kradio_plus_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/icons/hi64-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi64-app-kradio_plus_pause.png
new file mode 100644
index 0000000..fdd0aaf
--- /dev/null
+++ b/kradio3/plugins/timeshifter/icons/hi64-app-kradio_plus_pause.png
Binary files differ
diff --git a/kradio3/plugins/timeshifter/po/Makefile.am b/kradio3/plugins/timeshifter/po/Makefile.am
new file mode 100644
index 0000000..276fe4b
--- /dev/null
+++ b/kradio3/plugins/timeshifter/po/Makefile.am
@@ -0,0 +1,3 @@
+
+PACKAGE = kradio-timeshifter
+POFILES = AUTO
diff --git a/kradio3/plugins/timeshifter/po/de.po b/kradio3/plugins/timeshifter/po/de.po
new file mode 100644
index 0000000..66806f9
--- /dev/null
+++ b/kradio3/plugins/timeshifter/po/de.po
@@ -0,0 +1,91 @@
+# translation of de.po to
+# translation of kradio-timeshifter.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:41+0100\n"
+"PO-Revision-Date: 2006-11-12 18:24+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file timeshifter-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:22 timeshifter-configuration-ui.cpp:118
+#, no-c-format
+msgid "SetupDialogGeneral"
+msgstr "SetupDialogGeneral"
+
+#. i18n: file timeshifter-configuration-ui.ui line 72
+#: rc.cpp:6 rc.cpp:25 timeshifter-configuration-ui.cpp:119
+#, no-c-format
+msgid " MB"
+msgstr " MB"
+
+#. i18n: file timeshifter-configuration-ui.ui line 92
+#: rc.cpp:9 rc.cpp:28 timeshifter-configuration-ui.cpp:120
+#, no-c-format
+msgid "Maximum File Size"
+msgstr "maximale Dateigröße"
+
+#. i18n: file timeshifter-configuration-ui.ui line 100
+#: rc.cpp:12 rc.cpp:31 timeshifter-configuration-ui.cpp:121
+#, no-c-format
+msgid "Playback Mixer Device"
+msgstr "Wiedergabemixer"
+
+#. i18n: file timeshifter-configuration-ui.ui line 108
+#: rc.cpp:15 rc.cpp:34 timeshifter-configuration-ui.cpp:122
+#, no-c-format
+msgid "Temporary File"
+msgstr "Temporäre Datei"
+
+#. i18n: file timeshifter-configuration-ui.ui line 121
+#: rc.cpp:18 rc.cpp:37 timeshifter-configuration-ui.cpp:123
+#, no-c-format
+msgid "Playback Mixer Channel"
+msgstr "Wiedergabemixerkanal"
+
+#: timeshifter-configuration.cpp:138
+msgid "any ( * )"
+msgstr "alle ( * )"
+
+#: timeshifter-configuration.cpp:140
+msgid "TimeShifter Temporary File Selection"
+msgstr "Auswahl der temporären Datei für die zeitversetzte Wiedergabe"
+
+#: timeshifter-configuration.cpp:143
+msgid "Select TimeShifter Temporary File"
+msgstr "Auswahl der temporären Datei für die zeitversetzte Wiedergabe"
+
+#: timeshifter.cpp:31
+msgid "TimeShift Support"
+msgstr "Unterstützung für die Zeitversetzte Wiedergabe"
+
+#: timeshifter.cpp:36
+msgid "TimeShifter Plugin"
+msgstr "Plugin für die zeitversetzte Wiedergabe"
+
+#: timeshifter.cpp:121
+msgid "Timeshifter"
+msgstr "Zeitversetzte Wiedergabe"
+
+#: timeshifter.cpp:122
+msgid "Timeshifter Options"
+msgstr "Optionen für die zeitversetzte Wiedergabe"
+
+#: timeshifter.cpp:355
+msgid "TimeShifter::notifySoundStreamData: clients skipped %1 bytes. Data Lost"
+msgstr ""
+"TimeShifter::notifySoundStreamData: %1 bytes der Sounddaten wurden ignoriert "
+"und sind verloren"
+
+#: timeshifter.cpp:412
+msgid "internal stream, not stored"
+msgstr "interner, nicht aufgezeichneter Datenstrom"
diff --git a/kradio3/plugins/timeshifter/po/ru.po b/kradio3/plugins/timeshifter/po/ru.po
new file mode 100644
index 0000000..1f692e3
--- /dev/null
+++ b/kradio3/plugins/timeshifter/po/ru.po
@@ -0,0 +1,91 @@
+# translation of ru.po to
+# translation of kradio-timeshifter.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-12 18:20+0100\n"
+"PO-Revision-Date: 2006-11-08 12:19+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file timeshifter-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:22 timeshifter-configuration-ui.cpp:118
+#, no-c-format
+msgid "SetupDialogGeneral"
+msgstr "SetupDialogGeneral"
+
+#. i18n: file timeshifter-configuration-ui.ui line 72
+#: rc.cpp:6 rc.cpp:25 timeshifter-configuration-ui.cpp:119
+#, no-c-format
+msgid " MB"
+msgstr " Мб"
+
+#. i18n: file timeshifter-configuration-ui.ui line 92
+#: rc.cpp:9 rc.cpp:28 timeshifter-configuration-ui.cpp:120
+#, no-c-format
+msgid "Maximum File Size"
+msgstr "Размер файла, не более"
+
+#. i18n: file timeshifter-configuration-ui.ui line 100
+#: rc.cpp:12 rc.cpp:31 timeshifter-configuration-ui.cpp:121
+#, no-c-format
+msgid "Playback Mixer Device"
+msgstr "Устройство воспроизведения"
+
+#. i18n: file timeshifter-configuration-ui.ui line 108
+#: rc.cpp:15 rc.cpp:34 timeshifter-configuration-ui.cpp:122
+#, no-c-format
+msgid "Temporary File"
+msgstr "Временный файл"
+
+#. i18n: file timeshifter-configuration-ui.ui line 121
+#: rc.cpp:18 rc.cpp:37 timeshifter-configuration-ui.cpp:123
+#, no-c-format
+msgid "Playback Mixer Channel"
+msgstr "Канал воспроизведения"
+
+#: timeshifter-configuration.cpp:138
+msgid "any ( * )"
+msgstr "Все ( * )"
+
+#: timeshifter-configuration.cpp:140
+msgid "TimeShifter Temporary File Selection"
+msgstr "Выбор временного файла для реализации приостановки вещания"
+
+#: timeshifter-configuration.cpp:143
+msgid "Select TimeShifter Temporary File"
+msgstr "Выберите временный файл"
+
+#: timeshifter.cpp:31
+msgid "TimeShift Support"
+msgstr "Поддержка приостановки вещания"
+
+#: timeshifter.cpp:36
+msgid "TimeShifter Plugin"
+msgstr "Модуль приостановки вещания"
+
+#: timeshifter.cpp:121
+msgid "Timeshifter"
+msgstr "Приостановка"
+
+#: timeshifter.cpp:122
+msgid "Timeshifter Options"
+msgstr "Параметры приостановки вещания"
+
+#: timeshifter.cpp:355
+msgid "TimeShifter::notifySoundStreamData: clients skipped %1 bytes. Data Lost"
+msgstr ""
+"TimeShifter::notifySoundStreamData: клиенты пропустили %1 байт. Данные "
+"утеряны."
+
+#: timeshifter.cpp:412
+msgid "internal stream, not stored"
+msgstr ""
diff --git a/kradio3/plugins/timeshifter/timeshifter-configuration-ui.ui b/kradio3/plugins/timeshifter/timeshifter-configuration-ui.ui
new file mode 100644
index 0000000..3e3f4e4
--- /dev/null
+++ b/kradio3/plugins/timeshifter/timeshifter-configuration-ui.ui
@@ -0,0 +1,225 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>TimeShifterConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>TimeShifterConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>299</width>
+ <height>134</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>SetupDialogGeneral</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>spacer18_3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer18_3_2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>104</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSpinBox" row="1" column="2">
+ <property name="name">
+ <cstring>editTempFileSize</cstring>
+ </property>
+ <property name="suffix">
+ <string> MB</string>
+ </property>
+ <property name="maxValue">
+ <number>10000</number>
+ </property>
+ <property name="minValue">
+ <number>10</number>
+ </property>
+ <property name="lineStep">
+ <number>10</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>labelTempFileSize</cstring>
+ </property>
+ <property name="text">
+ <string>Maximum File Size</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>labelPlaybackMixerDevice</cstring>
+ </property>
+ <property name="text">
+ <string>Playback Mixer Device</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelTempFile</cstring>
+ </property>
+ <property name="text">
+ <string>Temporary File</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>editTempFile</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>labelPlaybackMixerChannel</cstring>
+ </property>
+ <property name="text">
+ <string>Playback Mixer Channel</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="3">
+ <property name="name">
+ <cstring>buttonSelectTempFile</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>26</width>
+ <height>26</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"fileopen"</iconset>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>comboPlaybackMixerDevice</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>comboPlaybackMixerChannel</cstring>
+ </property>
+ </widget>
+ <spacer row="3" column="3">
+ <property name="name">
+ <cstring>spacer18_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="3">
+ <property name="name">
+ <cstring>spacer18_3_4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>61</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>editTempFile</tabstop>
+ <tabstop>buttonSelectTempFile</tabstop>
+ <tabstop>comboPlaybackMixerChannel</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+ <include location="global" impldecl="in implementation">knuminput.h</include>
+</includes>
+<pixmapfunction>SmallIconSet</pixmapfunction>
+<layoutdefaults spacing="6" margin="0"/>
+</UI>
diff --git a/kradio3/plugins/timeshifter/timeshifter-configuration.cpp b/kradio3/plugins/timeshifter/timeshifter-configuration.cpp
new file mode 100644
index 0000000..828cc33
--- /dev/null
+++ b/kradio3/plugins/timeshifter/timeshifter-configuration.cpp
@@ -0,0 +1,203 @@
+/***************************************************************************
+ v4lradio-configuration.cpp - description
+ -------------------
+ begin : Fre Jun 20 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 <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/soundcard.h>
+
+#include <qspinbox.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qfile.h>
+#include <qpushbutton.h>
+
+#include <kfiledialog.h>
+#include <knuminput.h>
+#include <klocale.h>
+
+#include "../../src/include/utils.h"
+#include "../../src/include/gui_list_helper.h"
+#include "timeshifter-configuration.h"
+#include "timeshifter.h"
+
+TimeShifterConfiguration::TimeShifterConfiguration (QWidget *parent, TimeShifter *shifter)
+ : TimeShifterConfigurationUI(parent),
+ m_ignoreGUIChanges(false),
+ m_myControlChange(0),
+ m_PlaybackMixerHelper(comboPlaybackMixerDevice, StringListHelper::SORT_BY_DESCR),
+ m_PlaybackChannelHelper(comboPlaybackMixerChannel),
+ m_Shifter(shifter),
+ m_dirty(true)
+{
+ QObject::connect(buttonSelectTempFile, SIGNAL(clicked()),
+ this, SLOT(selectTempFile()));
+ QObject::connect(comboPlaybackMixerDevice, SIGNAL(activated(int)),
+ this, SLOT(slotComboPlaybackMixerSelected(int)));
+
+ connect(editTempFile, SIGNAL(textChanged(const QString&)), this, SLOT(slotSetDirty()));
+ connect(editTempFileSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty()));
+ connect(comboPlaybackMixerChannel, SIGNAL(activated( int )), this, SLOT(slotSetDirty()));
+ connect(comboPlaybackMixerDevice, SIGNAL(activated( int )), this, SLOT(slotSetDirty()));
+ slotCancel();
+}
+
+
+TimeShifterConfiguration::~TimeShifterConfiguration ()
+{
+}
+
+
+bool TimeShifterConfiguration::connectI (Interface *i)
+{
+ bool a = ISoundStreamClient::connectI(i);
+ return a;
+}
+
+
+bool TimeShifterConfiguration::disconnectI (Interface *i)
+{
+ bool a = ISoundStreamClient::disconnectI(i);
+ return a;
+}
+
+void TimeShifterConfiguration::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_notifyPlaybackChannelsChanged(this);
+ }
+}
+
+void TimeShifterConfiguration::noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid)
+{
+ if (i && pointer_valid && i->supportsPlayback() && m_Shifter) {
+ const QString &org_mid = m_Shifter->getPlaybackMixer();
+ bool org_present = m_PlaybackMixerHelper.contains(org_mid);
+ const QString &mid = org_present ? m_PlaybackMixerHelper.getCurrentItem() : org_mid;
+ const QString &org_ch = m_Shifter->getPlaybackMixerChannel();
+ const QString &ch = org_present ? m_PlaybackChannelHelper.getCurrentText() : org_ch;
+ setPlaybackMixer(mid, ch);
+ }
+}
+
+
+void TimeShifterConfiguration::noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid)
+{
+ if (i && pointer_valid && i->supportsPlayback()) {
+ setPlaybackMixer(m_Shifter->getPlaybackMixer(), m_Shifter->getPlaybackMixerChannel());
+ }
+}
+
+
+
+bool TimeShifterConfiguration::setPlaybackMixer(const QString &_mixer_id, const QString &Channel)
+{
+ QString mixer_id = _mixer_id;
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+
+ m_PlaybackMixerHelper.setData(getPlaybackClientDescriptions());
+ m_PlaybackMixerHelper.setCurrentItem(mixer_id);
+ mixer_id = m_PlaybackMixerHelper.getCurrentItem();
+
+ ISoundStreamClient *mixer = getSoundStreamClientWithID(mixer_id);
+ if (mixer) {
+ m_PlaybackChannelHelper.setData(mixer->getPlaybackChannels());
+ m_PlaybackChannelHelper.setCurrentText(m_PlaybackChannelHelper.contains(Channel) ? Channel : m_Shifter->getPlaybackMixerChannel());
+ }
+ labelPlaybackMixerChannel->setEnabled(mixer != NULL);
+ comboPlaybackMixerChannel->setEnabled(mixer != NULL);
+
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+// GUI Slots
+
+
+void TimeShifterConfiguration::selectTempFile()
+{
+ KFileDialog fd("/tmp/",
+ i18n("any ( * )").ascii(),
+ this,
+ i18n("TimeShifter Temporary File Selection").ascii(),
+ TRUE);
+ fd.setMode(KFile::File);
+ fd.setCaption (i18n("Select TimeShifter Temporary File"));
+
+ if (fd.exec() == QDialog::Accepted) {
+ editTempFile->setText(fd.selectedFile());
+ }
+}
+
+
+void TimeShifterConfiguration::slotComboPlaybackMixerSelected(int /*idx*/)
+{
+ if (m_ignoreGUIChanges) return;
+ setPlaybackMixer(m_PlaybackMixerHelper.getCurrentItem(), m_PlaybackChannelHelper.getCurrentText());
+}
+
+
+void TimeShifterConfiguration::slotOK()
+{
+ if (m_Shifter && m_dirty) {
+ m_Shifter->setTempFile(editTempFile->text(), editTempFileSize->value() * (Q_UINT64)(1024 * 1024));
+ m_Shifter->setPlaybackMixer(m_PlaybackMixerHelper.getCurrentItem(),
+ m_PlaybackChannelHelper.getCurrentText());
+ m_dirty = false;
+ }
+}
+
+
+void TimeShifterConfiguration::slotCancel()
+{
+ if (m_Shifter && m_dirty) {
+ editTempFile->setText(m_Shifter->getTempFileName());
+ editTempFileSize->setValue(m_Shifter->getTempFileMaxSize() / 1024 / 1024);
+
+ setPlaybackMixer(m_Shifter->getPlaybackMixer(), m_Shifter->getPlaybackMixerChannel());
+ m_dirty = false;
+ }
+}
+
+
+bool TimeShifterConfiguration::noticePlaybackChannelsChanged(const QString & client_id, const QStringList &/*channels*/)
+{
+ if (m_PlaybackMixerHelper.getCurrentItem() == client_id) {
+ setPlaybackMixer(client_id, m_PlaybackChannelHelper.getCurrentText());
+ }
+ return true;
+}
+
+
+void TimeShifterConfiguration::slotSetDirty()
+{
+ if (!m_ignoreGUIChanges) {
+ m_dirty = true;
+ }
+}
+
+void TimeShifterConfiguration::slotUpdateConfig()
+{
+ slotSetDirty();
+ slotCancel();
+}
+
+#include "timeshifter-configuration.moc"
diff --git a/kradio3/plugins/timeshifter/timeshifter-configuration.h b/kradio3/plugins/timeshifter/timeshifter-configuration.h
new file mode 100644
index 0000000..7d34c3d
--- /dev/null
+++ b/kradio3/plugins/timeshifter/timeshifter-configuration.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ v4lradio-configuration.h - description
+ -------------------
+ begin : Fre Jun 20 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_TIMESHIFTER_CONFIGURATION_H
+#define KRADIO_TIMESHIFTER_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "../../src/include/gui_list_helper.h"
+
+#include "timeshifter-configuration-ui.h"
+
+class QWidget;
+class TimeShifter;
+
+class TimeShifterConfiguration : public TimeShifterConfigurationUI,
+ public ISoundStreamClient
+{
+Q_OBJECT
+public :
+ TimeShifterConfiguration (QWidget *parent, TimeShifter *shifter);
+ ~TimeShifterConfiguration ();
+
+ bool connectI (Interface *i);
+ bool disconnectI (Interface *i);
+
+ void noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid);
+ void noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid);
+
+// ISoundStreamClient
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+ bool noticePlaybackChannelsChanged(const QString & /*client_id*/, const QStringList &/*channels*/);
+
+protected:
+
+ bool setPlaybackMixer(const QString &_mixer_id, const QString &Channel);
+
+
+protected slots:
+
+ void selectTempFile();
+ void slotComboPlaybackMixerSelected(int idx);
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+ void slotUpdateConfig();
+
+protected:
+
+ bool m_ignoreGUIChanges;
+ int m_myControlChange;
+
+ typedef GUIListHelper<QComboBox, QString> StringListHelper;
+ typedef GUISimpleListHelper<QComboBox> ChannelListHelper;
+
+ StringListHelper m_PlaybackMixerHelper;
+ ChannelListHelper m_PlaybackChannelHelper;
+
+ TimeShifter *m_Shifter;
+ bool m_dirty;
+};
+
+#endif
diff --git a/kradio3/plugins/timeshifter/timeshifter.cpp b/kradio3/plugins/timeshifter/timeshifter.cpp
new file mode 100644
index 0000000..bff1851
--- /dev/null
+++ b/kradio3/plugins/timeshifter/timeshifter.cpp
@@ -0,0 +1,455 @@
+/***************************************************************************
+ timeshifter.cpp - description
+ -------------------
+ begin : Mon May 16 13:39:31 CEST 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <klocale.h>
+#include <linux/soundcard.h>
+
+#include "../../src/include/utils.h"
+#include "timeshifter.h"
+#include "timeshifter-configuration.h"
+
+///////////////////////////////////////////////////////////////////////
+
+PLUGIN_LIBRARY_FUNCTIONS(TimeShifter, "kradio-timeshifter", i18n("TimeShift Support"));
+
+///////////////////////////////////////////////////////////////////////
+
+TimeShifter::TimeShifter (const QString &name)
+ : PluginBase(name, i18n("TimeShifter Plugin")),
+ m_TempFileName("/tmp/kradio-timeshifter-tempfile"),
+ m_TempFileMaxSize(256*1024*1024),
+ m_PlaybackMixerID(QString::null),
+ m_PlaybackMixerChannel("PCM"),
+ m_orgVolume(0.0),
+ m_PlaybackMetaData(0,0,0),
+ m_PlaybackDataLeftInBuffer(0),
+ m_RingBuffer(m_TempFileName, m_TempFileMaxSize)
+{
+}
+
+
+TimeShifter::~TimeShifter ()
+{
+}
+
+
+bool TimeShifter::connectI (Interface *i)
+{
+ bool a = PluginBase::connectI(i);
+ bool b = ISoundStreamClient::connectI(i);
+ return a || b;
+}
+
+
+bool TimeShifter::disconnectI (Interface *i)
+{
+ bool a = PluginBase::disconnectI(i);
+ bool b = ISoundStreamClient::disconnectI(i);
+ return a || b;
+}
+
+
+void TimeShifter::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_notifySoundStreamClosed(this);
+ s->register4_sendStartPlayback(this);
+ s->register4_sendStopPlayback(this);
+ s->register4_sendPausePlayback(this);
+ s->register4_notifySoundStreamData(this);
+ s->register4_notifyReadyForPlaybackData(this);
+ s->register4_querySoundStreamDescription(this);
+ s->register4_sendStartCaptureWithFormat(this);
+ s->register4_sendStopCapture(this);
+ }
+}
+
+
+void TimeShifter::saveState (KConfig *config) const
+{
+ config->setGroup(QString("timeshifter-") + name());
+
+ config->writeEntry("temp-file-name", m_TempFileName);
+ config->writeEntry("max-file-size", m_TempFileMaxSize / 1024 / 1024);
+
+ config->writeEntry("PlaybackMixerID", m_PlaybackMixerID);
+ config->writeEntry("PlaybackMixerChannel", m_PlaybackMixerChannel);
+}
+
+
+void TimeShifter::restoreState (KConfig *config)
+{
+ config->setGroup(QString("timeshifter-") + name());
+
+ QString fname = config->readEntry("temp-file-name", "/tmp/kradio-timeshifter-tempfile");
+ Q_UINT64 fsize = 1024 * 1024 * config->readNumEntry("max-file-size", 256);
+
+ QString mixerID = config->readEntry ("PlaybackMixerID", QString::null);
+ QString channel = config->readEntry ("PlaybackMixerChannel", "PCM");
+
+ setPlaybackMixer(mixerID, channel);
+ setTempFile(fname, fsize);
+
+ emit sigUpdateConfig();
+}
+
+
+ConfigPageInfo TimeShifter::createConfigurationPage()
+{
+ TimeShifterConfiguration *conf = new TimeShifterConfiguration(NULL, this);
+ QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig()));
+ return ConfigPageInfo (conf,
+ i18n("Timeshifter"),
+ i18n("Timeshifter Options"),
+ "kradio_pause");
+}
+
+AboutPageInfo TimeShifter::createAboutPage()
+{
+ return AboutPageInfo();
+}
+
+
+bool TimeShifter::noticeSoundStreamClosed(SoundStreamID id)
+{
+ return stopPlayback(id);
+}
+
+bool TimeShifter::startPlayback(SoundStreamID id)
+{
+ if (id == m_OrgStreamID) {
+ m_StreamPaused = false;
+ return true;
+ }
+ return false;
+}
+
+bool TimeShifter::stopPlayback(SoundStreamID id)
+{
+ if (id == m_NewStreamID) {
+
+ return sendStopPlayback(m_OrgStreamID);
+
+ } else if (id == m_OrgStreamID) {
+
+ SoundStreamID tmp_newID = m_NewStreamID;
+ SoundStreamID tmp_orgID = m_OrgStreamID;
+
+ m_OrgStreamID.invalidate();
+ m_NewStreamID.invalidate();
+
+ sendStopCapture(tmp_newID);
+ closeSoundStream(tmp_newID);
+ stopPlayback(tmp_newID);
+ m_RingBuffer.clear();
+ m_PlaybackMetaData = SoundMetaData(0,0,0);
+ m_PlaybackDataLeftInBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+
+bool TimeShifter::pausePlayback(SoundStreamID id)
+{
+ if (!m_OrgStreamID.isValid()) {
+ SoundStreamID orgid = id;
+ SoundStreamID newid = createNewSoundStream(orgid, false);
+ m_OrgStreamID = orgid;
+ m_NewStreamID = newid;
+ notifySoundStreamCreated(newid);
+ notifySoundStreamRedirected(orgid, newid);
+ queryPlaybackVolume(newid, m_orgVolume);
+ sendMute(newid);
+ sendPlaybackVolume(newid, 0);
+
+ m_NewStreamID.invalidate();
+ sendStopPlayback(newid);
+ m_NewStreamID = newid;
+
+ m_StreamPaused = true;
+
+ m_RingBuffer.clear();
+ m_PlaybackMetaData = SoundMetaData(0,0,0);
+ m_PlaybackDataLeftInBuffer = 0;
+
+ sendStartCaptureWithFormat(m_NewStreamID, m_SoundFormat, m_realSoundFormat);
+
+ ISoundStreamClient *playback_mixer = searchPlaybackMixer();
+ if (playback_mixer) {
+ playback_mixer->preparePlayback(m_OrgStreamID, m_PlaybackMixerChannel, /*active*/true, /*startimmediately*/ true);
+ m_PlaybackMixerID = playback_mixer->getSoundStreamClientID();
+ }
+
+ return true;
+
+ } else if (id == m_OrgStreamID) {
+ m_StreamPaused = !m_StreamPaused;
+ if (!m_StreamPaused) {
+// sendStartPlayback(m_OrgStreamID);
+ sendUnmute(m_OrgStreamID);
+ sendPlaybackVolume(m_OrgStreamID, m_orgVolume);
+ } else {
+ queryPlaybackVolume(m_OrgStreamID, m_orgVolume);
+ }
+ return true;
+ }
+ return false;
+}
+
+
+size_t TimeShifter::writeMetaDataToBuffer(const SoundMetaData &md, char *buffer, size_t buffer_size)
+{
+ Q_UINT64 pos = md.position();
+ time_t abs = md.absoluteTimestamp();
+ time_t rel = md.relativeTimestamp();
+ size_t url_len = md.url().url().length() + 1;
+ size_t req_size = sizeof(req_size) + sizeof(pos) + sizeof(abs) + sizeof(rel) + sizeof(url_len) + url_len;
+ if (req_size <= buffer_size) {
+ *(size_t*)buffer = req_size;
+ buffer += sizeof(req_size);
+ *(Q_UINT64*)buffer = pos;
+ buffer += sizeof(pos);
+ *(time_t*)buffer = abs;
+ buffer += sizeof(abs);
+ *(time_t*)buffer = rel;
+ buffer += sizeof(rel);
+ *(size_t*)buffer = url_len;
+ buffer += sizeof(url_len);
+ memcpy(buffer, md.url().url().ascii(), url_len);
+ buffer += url_len;
+ return req_size;
+ } else if (buffer_size >= sizeof(req_size)) {
+ *(size_t*)buffer = sizeof(req_size);
+ return sizeof(req_size);
+ } else {
+ return 0;
+ }
+}
+
+size_t TimeShifter::readMetaDataFromBuffer(SoundMetaData &md, const char *buffer, size_t buffer_size)
+{
+ size_t req_size = 0;
+ Q_UINT64 pos = 0;
+ time_t abs = 0;
+ time_t rel = 0;
+ size_t url_len = 0;
+ KURL url;
+ if (buffer_size >= sizeof(req_size)) {
+ req_size = *(size_t*)buffer;
+ buffer += sizeof(req_size);
+ if (req_size > sizeof(req_size)) {
+ pos = *(Q_UINT64*)buffer;
+ buffer += sizeof(Q_UINT64);
+ abs = *(time_t*)buffer;
+ buffer += sizeof(abs);
+ rel = *(time_t*)buffer;
+ buffer += sizeof(rel);
+ url_len = *(size_t*)buffer;
+ buffer += sizeof(url_len);
+ url = buffer;
+ buffer += url_len;
+ }
+ }
+ md = SoundMetaData(pos, rel, abs, url);
+ return req_size;
+}
+
+
+bool TimeShifter::noticeSoundStreamData(SoundStreamID id, const SoundFormat &/*sf*/, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md)
+{
+ if (id == m_NewStreamID) {
+ char buffer_meta[1024];
+ size_t meta_buffer_size = writeMetaDataToBuffer(md, buffer_meta, 1024);
+ size_t packet_size = meta_buffer_size + sizeof(size) + size;
+ if (packet_size > m_RingBuffer.getMaxSize())
+ return false;
+ Q_INT64 diff = m_RingBuffer.getFreeSize() - packet_size;
+ while (diff < 0) {
+ skipPacketInRingBuffer();
+ diff = m_RingBuffer.getFreeSize() - packet_size;
+ }
+ m_RingBuffer.addData(buffer_meta, meta_buffer_size);
+ m_RingBuffer.addData((const char*)&size, sizeof(size));
+ m_RingBuffer.addData(data, size);
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? size : min(consumed_size, size);
+ return true;
+ }
+ return false;
+}
+
+
+void TimeShifter::skipPacketInRingBuffer()
+{
+ if (m_PlaybackDataLeftInBuffer > 0) {
+ m_RingBuffer.removeData(m_PlaybackDataLeftInBuffer);
+ } else {
+ size_t meta_size = 0;
+ m_RingBuffer.takeData((char*)&meta_size, sizeof(meta_size));
+ m_RingBuffer.removeData(meta_size - sizeof(meta_size));
+ size_t packet_size = 0;
+ m_RingBuffer.takeData((char*)&packet_size, sizeof(packet_size));
+ m_RingBuffer.removeData(packet_size - sizeof(packet_size));
+ }
+}
+
+
+bool TimeShifter::noticeReadyForPlaybackData(SoundStreamID id, size_t free_size)
+{
+ if (id == m_OrgStreamID && !m_StreamPaused) {
+
+ while (!m_RingBuffer.error() && m_RingBuffer.getFillSize() > 0 && free_size > 0) {
+ if (m_PlaybackDataLeftInBuffer == 0) {
+ char meta_buffer[1024];
+ size_t &meta_size = *(size_t*)meta_buffer;
+ meta_size = 0;
+ m_RingBuffer.takeData(meta_buffer, sizeof(meta_size));
+ if (meta_size && meta_size <= 1024) {
+ m_RingBuffer.takeData(meta_buffer + sizeof(meta_size), meta_size - sizeof(meta_size));
+ readMetaDataFromBuffer(m_PlaybackMetaData, meta_buffer, meta_size);
+ } else {
+ m_RingBuffer.removeData(meta_size - sizeof(meta_size));
+ }
+
+ m_PlaybackDataLeftInBuffer = 0;
+ m_RingBuffer.takeData((char*)&m_PlaybackDataLeftInBuffer, sizeof(m_PlaybackDataLeftInBuffer));
+ }
+
+ const size_t buffer_size = 65536;
+ char buffer[buffer_size];
+
+ while (!m_RingBuffer.error() && m_PlaybackDataLeftInBuffer > 0 && free_size > 0) {
+ size_t s = m_PlaybackDataLeftInBuffer < free_size ? m_PlaybackDataLeftInBuffer : free_size;
+
+ if (s > buffer_size)
+ s = buffer_size;
+ s = m_RingBuffer.takeData(buffer, s);
+
+ size_t consumed_size = SIZE_T_DONT_CARE;
+ notifySoundStreamData(m_OrgStreamID, m_realSoundFormat, buffer, s, consumed_size, m_PlaybackMetaData);
+ if (consumed_size == SIZE_T_DONT_CARE)
+ consumed_size = s;
+
+ free_size -= consumed_size;
+ m_PlaybackDataLeftInBuffer -= consumed_size;
+ if (consumed_size < s) {
+ logError(i18n("TimeShifter::notifySoundStreamData: clients skipped %1 bytes. Data Lost").arg(s - consumed_size));
+ free_size = 0; // break condition for outer loop
+ break;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+
+ISoundStreamClient *TimeShifter::searchPlaybackMixer()
+{
+ ISoundStreamClient *playback_mixer = getSoundStreamClientWithID(m_PlaybackMixerID);
+
+ // some simple sort of autodetection if one mixer isn't present any more
+ if (!playback_mixer) {
+ QPtrList<ISoundStreamClient> playback_mixers = queryPlaybackMixers();
+ if (!playback_mixers.isEmpty())
+ playback_mixer = playback_mixers.first();
+ }
+ return playback_mixer;
+}
+
+
+bool TimeShifter::setPlaybackMixer(const QString &soundStreamClientID, const QString &ch)
+{
+ m_PlaybackMixerID = soundStreamClientID;
+ m_PlaybackMixerChannel = ch;
+
+ ISoundStreamClient *playback_mixer = searchPlaybackMixer();
+
+ float oldVolume;
+ if (m_OrgStreamID.isValid()) {
+ queryPlaybackVolume(m_OrgStreamID, oldVolume);
+ sendStopPlayback(m_OrgStreamID);
+ sendReleasePlayback(m_OrgStreamID);
+ }
+
+ if (playback_mixer)
+ playback_mixer->preparePlayback(m_OrgStreamID, m_PlaybackMixerChannel, /*active*/true, /*start_imm*/false);
+
+ if (m_OrgStreamID.isValid()) {
+ sendStartPlayback(m_OrgStreamID);
+ sendPlaybackVolume(m_OrgStreamID, oldVolume);
+ }
+
+ return true;
+}
+
+
+void TimeShifter::setTempFile(const QString &filename, Q_UINT64 s)
+{
+ m_RingBuffer.clear();
+ m_RingBuffer.resize(m_TempFileName = filename, m_TempFileMaxSize = s);
+ m_PlaybackMetaData = SoundMetaData(0,0,0, i18n("internal stream, not stored"));
+ m_PlaybackDataLeftInBuffer = 0;
+}
+
+bool TimeShifter::getSoundStreamDescription(SoundStreamID id, QString &descr) const
+{
+ if (id == m_NewStreamID) {
+ descr = name();
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool TimeShifter::startCaptureWithFormat(
+ SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format
+)
+{
+ if (id == m_OrgStreamID) {
+ if (force_format && m_realSoundFormat != proposed_format) {
+ sendStopCapture(m_NewStreamID);
+ sendStartCaptureWithFormat(m_NewStreamID, proposed_format, m_realSoundFormat);
+ }
+ real_format = m_realSoundFormat;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool TimeShifter::stopCapture(SoundStreamID id)
+{
+ if (id == m_OrgStreamID) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+#include "timeshifter.moc"
diff --git a/kradio3/plugins/timeshifter/timeshifter.h b/kradio3/plugins/timeshifter/timeshifter.h
new file mode 100644
index 0000000..32c3837
--- /dev/null
+++ b/kradio3/plugins/timeshifter/timeshifter.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ timeshifter.h - description
+ -------------------
+ begin : May 16 2005
+ copyright : (C) 2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_TIMESHIFTER_H
+#define KRADIO_TIMESHIFTER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/plugins.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "../../src/include/fileringbuffer.h"
+
+
+class TimeShifter : public QObject,
+ public PluginBase,
+ public ISoundStreamClient
+{
+Q_OBJECT
+public:
+ TimeShifter (const QString &name);
+ virtual ~TimeShifter ();
+
+ virtual bool connectI (Interface *);
+ virtual bool disconnectI (Interface *);
+
+ virtual QString pluginClassName() const { return "TimeShifter"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ // config
+
+ const QString &getPlaybackMixer() const { return m_PlaybackMixerID; }
+ const QString &getPlaybackMixerChannel() const { return m_PlaybackMixerChannel; }
+ const QString &getTempFileName() const { return m_TempFileName; }
+ Q_UINT64 getTempFileMaxSize() const { return m_TempFileMaxSize; }
+
+ void setTempFile(const QString &filename, Q_UINT64 s);
+ bool setPlaybackMixer(const QString &soundStreamClientID, const QString &ch);
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+protected:
+
+ ISoundStreamClient *searchPlaybackMixer();
+
+ size_t writeMetaDataToBuffer(const SoundMetaData &md, char *buffer, size_t buffer_size);
+ size_t readMetaDataFromBuffer(SoundMetaData &md, const char *buffer, size_t buffer_size);
+ void skipPacketInRingBuffer();
+
+ // SoundStreamClient
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format);
+ bool stopCapture(SoundStreamID id);
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool startPlayback(SoundStreamID id);
+ bool stopPlayback(SoundStreamID id);
+ bool pausePlayback(SoundStreamID id);
+ bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md);
+ bool noticeReadyForPlaybackData(SoundStreamID id, size_t size);
+
+ bool getSoundStreamDescription(SoundStreamID id, QString &descr) const;
+
+ // FIXME: react on redirect request
+
+signals:
+
+ void sigUpdateConfig();
+
+protected:
+
+ QString m_TempFileName;
+ size_t m_TempFileMaxSize;
+ SoundFormat m_SoundFormat;
+ SoundFormat m_realSoundFormat;
+
+ QString m_PlaybackMixerID;
+ QString m_PlaybackMixerChannel;
+
+ QString m_StreamFile;
+ bool m_StreamPaused;
+ SoundStreamID m_OrgStreamID;
+ SoundStreamID m_NewStreamID;
+ SoundFormat m_RealSoundFormat;
+ float m_orgVolume;
+
+ SoundMetaData m_PlaybackMetaData;
+ size_t m_PlaybackDataLeftInBuffer;
+
+ FileRingBuffer m_RingBuffer;
+};
+
+#endif
diff --git a/kradio3/plugins/v4lradio/Makefile.am b/kradio3/plugins/v4lradio/Makefile.am
new file mode 100644
index 0000000..093d346
--- /dev/null
+++ b/kradio3/plugins/v4lradio/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = po .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libkradio_LTLIBRARIES = libv4lradio.la
+libv4lradio_la_SOURCES = v4lcfg_interfaces.cpp v4lradio-configuration.cpp \
+ v4lradio-configuration-ui.ui v4lradio.cpp
+libv4lradio_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+
+noinst_HEADERS = v4lcfg_interfaces.h v4lradio-configuration.h v4lradio.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/kradio-v4lradio.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-v4lradio.pot
diff --git a/kradio3/plugins/v4lradio/linux/videodev.h b/kradio3/plugins/v4lradio/linux/videodev.h
new file mode 100644
index 0000000..e16a8a8
--- /dev/null
+++ b/kradio3/plugins/v4lradio/linux/videodev.h
@@ -0,0 +1,432 @@
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+#include <linux/types.h>
+#include <linux/version.h>
+//#include <linux/device.h>
+
+//#define HAVE_V4L2 1
+//#include <linux/videodev2.h>
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+#include <linux/mm.h>
+
+struct video_device
+{
+ /* device info */
+ struct device *dev;
+ char name[32];
+ int type; /* v4l1 */
+ int type2; /* v4l2 */
+ int hardware;
+ int minor;
+
+ /* device ops + callbacks */
+ struct file_operations *fops;
+ void (*release)(struct video_device *vfd);
+
+
+#if 1 /* to be removed in 2.7.x */
+ /* obsolete -- fops->owner is used instead */
+ struct module *owner;
+ /* dev->driver_data will be used instead some day.
+ * Use the video_{get|set}_drvdata() helper functions,
+ * so the switch over will be transparent for you.
+ * Or use {pci|usb}_{get|set}_drvdata() directly. */
+ void *priv;
+#endif
+
+ /* for videodev.c intenal usage -- please don't touch */
+ int users; /* video_exclusive_{open|close} ... */
+ struct semaphore lock; /* ... helper function uses these */
+ char devfs_name[64]; /* devfs */
+ struct class_device class_dev; /* sysfs */
+};
+
+#define VIDEO_MAJOR 81
+
+#define VFL_TYPE_GRABBER 0
+#define VFL_TYPE_VBI 1
+#define VFL_TYPE_RADIO 2
+#define VFL_TYPE_VTX 3
+
+extern int video_register_device(struct video_device *, int type, int nr);
+extern void video_unregister_device(struct video_device *);
+extern struct video_device* video_devdata(struct file*);
+
+#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
+static inline void
+video_device_create_file(struct video_device *vfd,
+ struct class_device_attribute *attr)
+{
+ class_device_create_file(&vfd->class_dev, attr);
+}
+
+/* helper functions to alloc / release struct video_device, the
+ later can be used for video_device->release() */
+struct video_device *video_device_alloc(void);
+void video_device_release(struct video_device *vfd);
+
+/* helper functions to access driver private data. */
+static inline void *video_get_drvdata(struct video_device *dev)
+{
+ return dev->priv;
+}
+
+static inline void video_set_drvdata(struct video_device *dev, void *data)
+{
+ dev->priv = data;
+}
+
+extern int video_exclusive_open(struct inode *inode, struct file *file);
+extern int video_exclusive_release(struct inode *inode, struct file *file);
+extern int video_usercopy(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg));
+#endif /* __KERNEL__ */
+
+#define VID_TYPE_CAPTURE 1 /* Can capture */
+#define VID_TYPE_TUNER 2 /* Can tune */
+#define VID_TYPE_TELETEXT 4 /* Does teletext */
+#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
+#define VID_TYPE_CLIPPING 32 /* Can clip */
+#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
+#define VID_TYPE_SCALES 128 /* Scalable */
+#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
+#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */
+#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */
+#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */
+#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
+#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
+
+struct video_capability
+{
+ char name[32];
+ int type;
+ int channels; /* Num channels */
+ int audios; /* Num audio devices */
+ int maxwidth; /* Supported width */
+ int maxheight; /* And height */
+ int minwidth; /* Supported width */
+ int minheight; /* And height */
+};
+
+
+struct video_channel
+{
+ int channel;
+ char name[32];
+ int tuners;
+ __u32 flags;
+#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
+#define VIDEO_VC_AUDIO 2 /* Channel has audio */
+ __u16 type;
+#define VIDEO_TYPE_TV 1
+#define VIDEO_TYPE_CAMERA 2
+ __u16 norm; /* Norm set by channel */
+};
+
+struct video_tuner
+{
+ int tuner;
+ char name[32];
+ unsigned long rangelow, rangehigh; /* Tuner range */
+ __u32 flags;
+#define VIDEO_TUNER_PAL 1
+#define VIDEO_TUNER_NTSC 2
+#define VIDEO_TUNER_SECAM 4
+#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
+#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */
+#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
+#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */
+#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */
+ __u16 mode; /* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL 0
+#define VIDEO_MODE_NTSC 1
+#define VIDEO_MODE_SECAM 2
+#define VIDEO_MODE_AUTO 3
+ __u16 signal; /* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+ __u16 brightness;
+ __u16 hue;
+ __u16 colour;
+ __u16 contrast;
+ __u16 whiteness; /* Black and white only */
+ __u16 depth; /* Capture depth */
+ __u16 palette; /* Palette in use */
+#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
+#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
+#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
+#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
+#define VIDEO_PALETTE_YUYV 8
+#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420 10
+#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
+#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
+};
+
+struct video_audio
+{
+ int audio; /* Audio channel */
+ __u16 volume; /* If settable */
+ __u16 bass, treble;
+ __u32 flags;
+#define VIDEO_AUDIO_MUTE 1
+#define VIDEO_AUDIO_MUTABLE 2
+#define VIDEO_AUDIO_VOLUME 4
+#define VIDEO_AUDIO_BASS 8
+#define VIDEO_AUDIO_TREBLE 16
+#define VIDEO_AUDIO_BALANCE 32
+ char name[16];
+#define VIDEO_SOUND_MONO 1
+#define VIDEO_SOUND_STEREO 2
+#define VIDEO_SOUND_LANG1 4
+#define VIDEO_SOUND_LANG2 8
+ __u16 mode;
+ __u16 balance; /* Stereo balance */
+ __u16 step; /* Step actual volume uses */
+};
+
+struct video_clip
+{
+ __s32 x,y;
+ __s32 width, height;
+ struct video_clip *next; /* For user use/driver use only */
+};
+
+struct video_window
+{
+ __u32 x,y; /* Position of window */
+ __u32 width,height; /* Its size */
+ __u32 chromakey;
+ __u32 flags;
+ struct video_clip *clips; /* Set only */
+ int clipcount;
+#define VIDEO_WINDOW_INTERLACE 1
+#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */
+#define VIDEO_CLIP_BITMAP -1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE (128 * 625)
+};
+
+struct video_capture
+{
+ __u32 x,y; /* Offsets into image */
+ __u32 width, height; /* Area to capture */
+ __u16 decimation; /* Decimation divider */
+ __u16 flags; /* Flags for capture */
+#define VIDEO_CAPTURE_ODD 0 /* Temporal */
+#define VIDEO_CAPTURE_EVEN 1
+};
+
+struct video_buffer
+{
+ void *base;
+ int height,width;
+ int depth;
+ int bytesperline;
+};
+
+struct video_mmap
+{
+ unsigned int frame; /* Frame (0 - n) for double buffer */
+ int height,width;
+ unsigned int format; /* should be VIDEO_PALETTE_* */
+};
+
+struct video_key
+{
+ __u8 key[8];
+ __u32 flags;
+};
+
+
+#define VIDEO_MAX_FRAME 32
+
+struct video_mbuf
+{
+ int size; /* Total memory to map */
+ int frames; /* Frames */
+ int offsets[VIDEO_MAX_FRAME];
+};
+
+
+#define VIDEO_NO_UNIT (-1)
+
+
+struct video_unit
+{
+ int video; /* Video minor */
+ int vbi; /* VBI minor */
+ int radio; /* Radio minor */
+ int audio; /* Audio minor */
+ int teletext; /* Teletext minor */
+};
+
+struct vbi_format {
+ __u32 sampling_rate; /* in Hz */
+ __u32 samples_per_line;
+ __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */
+ __s32 start[2]; /* starting line for each frame */
+ __u32 count[2]; /* count of lines for each frame */
+ __u32 flags;
+#define VBI_UNSYNC 1 /* can distingues between top/bottom field */
+#define VBI_INTERLACED 2 /* lines are interlaced */
+};
+
+/* video_info is biased towards hardware mpeg encode/decode */
+/* but it could apply generically to any hardware compressor/decompressor */
+struct video_info
+{
+ __u32 frame_count; /* frames output since decode/encode began */
+ __u32 h_size; /* current unscaled horizontal size */
+ __u32 v_size; /* current unscaled veritcal size */
+ __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */
+ __u32 picture_type; /* current picture type */
+ __u32 temporal_reference; /* current temporal reference */
+ __u8 user_data[256]; /* user data last found in compressed stream */
+ /* user_data[0] contains user data flags, user_data[1] has count */
+};
+
+/* generic structure for setting playback modes */
+struct video_play_mode
+{
+ int mode;
+ int p1;
+ int p2;
+};
+
+/* for loading microcode / fpga programming */
+struct video_code
+{
+ char loadwhat[16]; /* name or tag of file being passed */
+ int datasize;
+ __u8 *data;
+};
+
+#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
+#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
+#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */
+#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
+#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
+#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
+#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
+#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
+#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */
+#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
+#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
+#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
+#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
+#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
+#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
+#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
+#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */
+#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */
+#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */
+#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */
+#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */
+#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */
+#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */
+#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */
+#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */
+#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */
+
+
+#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
+
+/* VIDIOCSWRITEMODE */
+#define VID_WRITE_MPEG_AUD 0
+#define VID_WRITE_MPEG_VID 1
+#define VID_WRITE_OSD 2
+#define VID_WRITE_TTX 3
+#define VID_WRITE_CC 4
+#define VID_WRITE_MJPEG 5
+
+/* VIDIOCSPLAYMODE */
+#define VID_PLAY_VID_OUT_MODE 0
+ /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */
+#define VID_PLAY_GENLOCK 1
+ /* p1: 0 = OFF, 1 = ON */
+ /* p2: GENLOCK FINE DELAY value */
+#define VID_PLAY_NORMAL 2
+#define VID_PLAY_PAUSE 3
+#define VID_PLAY_SINGLE_FRAME 4
+#define VID_PLAY_FAST_FORWARD 5
+#define VID_PLAY_SLOW_MOTION 6
+#define VID_PLAY_IMMEDIATE_NORMAL 7
+#define VID_PLAY_SWITCH_CHANNELS 8
+#define VID_PLAY_FREEZE_FRAME 9
+#define VID_PLAY_STILL_MODE 10
+#define VID_PLAY_MASTER_MODE 11
+ /* p1: see below */
+#define VID_PLAY_MASTER_NONE 1
+#define VID_PLAY_MASTER_VIDEO 2
+#define VID_PLAY_MASTER_AUDIO 3
+#define VID_PLAY_ACTIVE_SCANLINES 12
+ /* p1 = first active; p2 = last active */
+#define VID_PLAY_RESET 13
+#define VID_PLAY_END_MARK 14
+
+
+
+#define VID_HARDWARE_BT848 1
+#define VID_HARDWARE_QCAM_BW 2
+#define VID_HARDWARE_PMS 3
+#define VID_HARDWARE_QCAM_C 4
+#define VID_HARDWARE_PSEUDO 5
+#define VID_HARDWARE_SAA5249 6
+#define VID_HARDWARE_AZTECH 7
+#define VID_HARDWARE_SF16MI 8
+#define VID_HARDWARE_RTRACK 9
+#define VID_HARDWARE_ZOLTRIX 10
+#define VID_HARDWARE_SAA7146 11
+#define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */
+#define VID_HARDWARE_RTRACK2 13
+#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */
+#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */
+#define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */
+#define VID_HARDWARE_BROADWAY 17 /* Broadway project */
+#define VID_HARDWARE_GEMTEK 18
+#define VID_HARDWARE_TYPHOON 19
+#define VID_HARDWARE_VINO 20 /* SGI Indy Vino */
+#define VID_HARDWARE_CADET 21 /* Cadet radio */
+#define VID_HARDWARE_TRUST 22 /* Trust FM Radio */
+#define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */
+#define VID_HARDWARE_CPIA 24
+#define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */
+#define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */
+#define VID_HARDWARE_OV511 27
+#define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */
+#define VID_HARDWARE_W9966 29
+#define VID_HARDWARE_SE401 30 /* SE401 USB webcams */
+#define VID_HARDWARE_PWC 31 /* Philips webcams */
+#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */
+#define VID_HARDWARE_CPIA2 33
+#define VID_HARDWARE_VICAM 34
+#define VID_HARDWARE_SF16FMR2 35
+#endif /* __LINUX_VIDEODEV_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/kradio3/plugins/v4lradio/linux/videodev2.h b/kradio3/plugins/v4lradio/linux/videodev2.h
new file mode 100644
index 0000000..c41831a
--- /dev/null
+++ b/kradio3/plugins/v4lradio/linux/videodev2.h
@@ -0,0 +1,940 @@
+#ifndef __LINUX_VIDEODEV2_H
+#define __LINUX_VIDEODEV2_H
+/*
+ * Video for Linux Two
+ *
+ * Header file for v4l or V4L2 drivers and applications, for
+ * Linux kernels 2.2.x or 2.4.x.
+ *
+ * See http://bytesex.org/v4l/ for API specs and other
+ * v4l2 documentation.
+ *
+ * Author: Bill Dirks <bdirks@pacbell.net>
+ * Justin Schoeman
+ * et al.
+ */
+
+#include <asm/types.h>
+#ifdef __KERNEL__
+#include <linux/time.h> /* need struct timeval */
+#endif
+
+/*
+ * M I S C E L L A N E O U S
+ */
+
+/* Four-character-code (FOURCC) */
+#define v4l2_fourcc(a,b,c,d)\
+ (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
+
+/*
+ * E N U M S
+ */
+enum v4l2_field {
+ V4L2_FIELD_ANY = 0, /* driver can choose from none,
+ top, bottom, interlaced
+ depending on whatever it thinks
+ is approximate ... */
+ V4L2_FIELD_NONE = 1, /* this device has no fields ... */
+ V4L2_FIELD_TOP = 2, /* top field only */
+ V4L2_FIELD_BOTTOM = 3, /* bottom field only */
+ V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */
+ V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one
+ buffer, top-bottom order */
+ V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */
+ V4L2_FIELD_ALTERNATE = 7 /* both fields alternating into
+ separate buffers */
+};
+#define V4L2_FIELD_HAS_TOP(field) \
+ ((field) == V4L2_FIELD_TOP ||\
+ (field) == V4L2_FIELD_INTERLACED ||\
+ (field) == V4L2_FIELD_SEQ_TB ||\
+ (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTTOM(field) \
+ ((field) == V4L2_FIELD_BOTTOM ||\
+ (field) == V4L2_FIELD_INTERLACED ||\
+ (field) == V4L2_FIELD_SEQ_TB ||\
+ (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTH(field) \
+ ((field) == V4L2_FIELD_INTERLACED ||\
+ (field) == V4L2_FIELD_SEQ_TB ||\
+ (field) == V4L2_FIELD_SEQ_BT)
+
+enum v4l2_buf_type {
+ V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
+ V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
+ V4L2_BUF_TYPE_VBI_CAPTURE = 4,
+ V4L2_BUF_TYPE_VBI_OUTPUT = 5,
+ V4L2_BUF_TYPE_PRIVATE = 0x80
+};
+
+enum v4l2_ctrl_type {
+ V4L2_CTRL_TYPE_INTEGER = 1,
+ V4L2_CTRL_TYPE_BOOLEAN = 2,
+ V4L2_CTRL_TYPE_MENU = 3,
+ V4L2_CTRL_TYPE_BUTTON = 4
+};
+
+enum v4l2_tuner_type {
+ V4L2_TUNER_RADIO = 1,
+ V4L2_TUNER_ANALOG_TV = 2
+};
+
+enum v4l2_memory {
+ V4L2_MEMORY_MMAP = 1,
+ V4L2_MEMORY_USERPTR = 2,
+ V4L2_MEMORY_OVERLAY = 3
+};
+
+/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
+enum v4l2_colorspace {
+ /* ITU-R 601 -- broadcast NTSC/PAL */
+ V4L2_COLORSPACE_SMPTE170M = 1,
+
+ /* 1125-Line (US) HDTV */
+ V4L2_COLORSPACE_SMPTE240M = 2,
+
+ /* HD and modern captures. */
+ V4L2_COLORSPACE_REC709 = 3,
+
+ /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
+ V4L2_COLORSPACE_BT878 = 4,
+
+ /* These should be useful. Assume 601 extents. */
+ V4L2_COLORSPACE_470_SYSTEM_M = 5,
+ V4L2_COLORSPACE_470_SYSTEM_BG = 6,
+
+ /* I know there will be cameras that send this. So, this is
+ * unspecified chromaticities and full 0-255 on each of the
+ * Y'CbCr components
+ */
+ V4L2_COLORSPACE_JPEG = 7,
+
+ /* For RGB colourspaces, this is probably a good start. */
+ V4L2_COLORSPACE_SRGB = 8
+};
+
+enum v4l2_priority {
+ V4L2_PRIORITY_UNSET = 0, /* not initialized */
+ V4L2_PRIORITY_BACKGROUND = 1,
+ V4L2_PRIORITY_INTERACTIVE = 2,
+ V4L2_PRIORITY_RECORD = 3,
+ V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE
+};
+
+struct v4l2_rect {
+ __s32 left;
+ __s32 top;
+ __s32 width;
+ __s32 height;
+};
+
+struct v4l2_fract {
+ __u32 numerator;
+ __u32 denominator;
+};
+
+/*
+ * D R I V E R C A P A B I L I T I E S
+ */
+struct v4l2_capability
+{
+ __u8 driver[16]; /* i.e. "bttv" */
+ __u8 card[32]; /* i.e. "Hauppauge WinTV" */
+ __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
+ __u32 version; /* should use KERNEL_VERSION() */
+ __u32 capabilities; /* Device capabilities */
+ __u32 reserved[4];
+};
+
+/* Values for 'capabilities' field */
+#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */
+#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */
+
+#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */
+#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */
+#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */
+
+#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */
+#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */
+#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */
+
+/*
+ * V I D E O I M A G E F O R M A T
+ */
+
+struct v4l2_pix_format
+{
+ __u32 width;
+ __u32 height;
+ __u32 pixelformat;
+ enum v4l2_field field;
+ __u32 bytesperline; /* for padding, zero if unused */
+ __u32 sizeimage;
+ enum v4l2_colorspace colorspace;
+ __u32 priv; /* private data, depends on pixelformat */
+};
+
+/* Pixel format FOURCC depth Description */
+#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */
+#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */
+#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */
+#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */
+#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */
+#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */
+#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */
+#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */
+#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */
+#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */
+#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */
+#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */
+#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */
+#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */
+#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */
+
+/* two planes -- one Y, one Cr + Cb interleaved */
+#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */
+#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */
+
+/* The following formats are not defined in the V4L2 specification */
+#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */
+#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */
+#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */
+
+/* compressed formats */
+#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */
+#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */
+#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */
+#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */
+
+/* Vendor-specific formats */
+#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
+
+/*
+ * F O R M A T E N U M E R A T I O N
+ */
+struct v4l2_fmtdesc
+{
+ __u32 index; /* Format number */
+ enum v4l2_buf_type type; /* buffer type */
+ __u32 flags;
+ __u8 description[32]; /* Description string */
+ __u32 pixelformat; /* Format fourcc */
+ __u32 reserved[4];
+};
+
+#define V4L2_FMT_FLAG_COMPRESSED 0x0001
+
+
+/*
+ * T I M E C O D E
+ */
+struct v4l2_timecode
+{
+ __u32 type;
+ __u32 flags;
+ __u8 frames;
+ __u8 seconds;
+ __u8 minutes;
+ __u8 hours;
+ __u8 userbits[4];
+};
+
+/* Type */
+#define V4L2_TC_TYPE_24FPS 1
+#define V4L2_TC_TYPE_25FPS 2
+#define V4L2_TC_TYPE_30FPS 3
+#define V4L2_TC_TYPE_50FPS 4
+#define V4L2_TC_TYPE_60FPS 5
+
+/* Flags */
+#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */
+#define V4L2_TC_FLAG_COLORFRAME 0x0002
+#define V4L2_TC_USERBITS_field 0x000C
+#define V4L2_TC_USERBITS_USERDEFINED 0x0000
+#define V4L2_TC_USERBITS_8BITCHARS 0x0008
+/* The above is based on SMPTE timecodes */
+
+
+/*
+ * C O M P R E S S I O N P A R A M E T E R S
+ */
+#if 0
+/* ### generic compression settings don't work, there is too much
+ * ### codec-specific stuff. Maybe reuse that for MPEG codec settings
+ * ### later ... */
+struct v4l2_compression
+{
+ __u32 quality;
+ __u32 keyframerate;
+ __u32 pframerate;
+ __u32 reserved[5];
+
+/* what we'll need for MPEG, extracted from some postings on
+ the v4l list (Gert Vervoort, PlasmaJohn).
+
+system stream:
+ - type: elementary stream(ES), packatised elementary stream(s) (PES)
+ program stream(PS), transport stream(TS)
+ - system bitrate
+ - PS packet size (DVD: 2048 bytes, VCD: 2324 bytes)
+ - TS video PID
+ - TS audio PID
+ - TS PCR PID
+ - TS system information tables (PAT, PMT, CAT, NIT and SIT)
+ - (MPEG-1 systems stream vs. MPEG-2 program stream (TS not supported
+ by MPEG-1 systems)
+
+audio:
+ - type: MPEG (+Layer I,II,III), AC-3, LPCM
+ - bitrate
+ - sampling frequency (DVD: 48 Khz, VCD: 44.1 KHz, 32 kHz)
+ - Trick Modes? (ff, rew)
+ - Copyright
+ - Inverse Telecine
+
+video:
+ - picturesize (SIF, 1/2 D1, 2/3 D1, D1) and PAL/NTSC norm can be set
+ through excisting V4L2 controls
+ - noise reduction, parameters encoder specific?
+ - MPEG video version: MPEG-1, MPEG-2
+ - GOP (Group Of Pictures) definition:
+ - N: number of frames per GOP
+ - M: distance between reference (I,P) frames
+ - open/closed GOP
+ - quantiser matrix: inter Q matrix (64 bytes) and intra Q matrix (64 bytes)
+ - quantiser scale: linear or logarithmic
+ - scanning: alternate or zigzag
+ - bitrate mode: CBR (constant bitrate) or VBR (variable bitrate).
+ - target video bitrate for CBR
+ - target video bitrate for VBR
+ - maximum video bitrate for VBR - min. quantiser value for VBR
+ - max. quantiser value for VBR
+ - adaptive quantisation value
+ - return the number of bytes per GOP or bitrate for bitrate monitoring
+
+*/
+};
+#endif
+
+struct v4l2_jpegcompression
+{
+ int quality;
+
+ int APPn; /* Number of APP segment to be written,
+ * must be 0..15 */
+ int APP_len; /* Length of data in JPEG APPn segment */
+ char APP_data[60]; /* Data in the JPEG APPn segment. */
+
+ int COM_len; /* Length of data in JPEG COM segment */
+ char COM_data[60]; /* Data in JPEG COM segment */
+
+ __u32 jpeg_markers; /* Which markers should go into the JPEG
+ * output. Unless you exactly know what
+ * you do, leave them untouched.
+ * Inluding less markers will make the
+ * resulting code smaller, but there will
+ * be fewer aplications which can read it.
+ * The presence of the APP and COM marker
+ * is influenced by APP_len and COM_len
+ * ONLY, not by this property! */
+
+#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
+#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
+#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
+#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */
+#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will
+ * allways use APP0 */
+};
+
+
+/*
+ * M E M O R Y - M A P P I N G B U F F E R S
+ */
+struct v4l2_requestbuffers
+{
+ __u32 count;
+ enum v4l2_buf_type type;
+ enum v4l2_memory memory;
+ __u32 reserved[2];
+};
+
+struct v4l2_buffer
+{
+ __u32 index;
+ enum v4l2_buf_type type;
+ __u32 bytesused;
+ __u32 flags;
+ enum v4l2_field field;
+ struct timeval timestamp;
+ struct v4l2_timecode timecode;
+ __u32 sequence;
+
+ /* memory location */
+ enum v4l2_memory memory;
+ union {
+ __u32 offset;
+ unsigned long userptr;
+ } m;
+ __u32 length;
+
+ __u32 reserved[2];
+};
+
+/* Flags for 'flags' field */
+#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */
+#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */
+#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */
+#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */
+#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */
+#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */
+#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */
+
+/*
+ * O V E R L A Y P R E V I E W
+ */
+struct v4l2_framebuffer
+{
+ __u32 capability;
+ __u32 flags;
+/* FIXME: in theory we should pass something like PCI device + memory
+ * region + offset instead of some physical address */
+ void* base;
+ struct v4l2_pix_format fmt;
+};
+/* Flags for the 'capability' field. Read only */
+#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001
+#define V4L2_FBUF_CAP_CHROMAKEY 0x0002
+#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004
+#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008
+/* Flags for the 'flags' field. */
+#define V4L2_FBUF_FLAG_PRIMARY 0x0001
+#define V4L2_FBUF_FLAG_OVERLAY 0x0002
+#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004
+
+struct v4l2_clip
+{
+ struct v4l2_rect c;
+ struct v4l2_clip *next;
+};
+
+struct v4l2_window
+{
+ struct v4l2_rect w;
+ enum v4l2_field field;
+ __u32 chromakey;
+ struct v4l2_clip *clips;
+ __u32 clipcount;
+ void *bitmap;
+};
+
+
+/*
+ * C A P T U R E P A R A M E T E R S
+ */
+struct v4l2_captureparm
+{
+ __u32 capability; /* Supported modes */
+ __u32 capturemode; /* Current mode */
+ struct v4l2_fract timeperframe; /* Time per frame in .1us units */
+ __u32 extendedmode; /* Driver-specific extensions */
+ __u32 readbuffers; /* # of buffers for read */
+ __u32 reserved[4];
+};
+/* Flags for 'capability' and 'capturemode' fields */
+#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */
+#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */
+
+struct v4l2_outputparm
+{
+ __u32 capability; /* Supported modes */
+ __u32 outputmode; /* Current mode */
+ struct v4l2_fract timeperframe; /* Time per frame in seconds */
+ __u32 extendedmode; /* Driver-specific extensions */
+ __u32 writebuffers; /* # of buffers for write */
+ __u32 reserved[4];
+};
+
+/*
+ * I N P U T I M A G E C R O P P I N G
+ */
+
+struct v4l2_cropcap {
+ enum v4l2_buf_type type;
+ struct v4l2_rect bounds;
+ struct v4l2_rect defrect;
+ struct v4l2_fract pixelaspect;
+};
+
+struct v4l2_crop {
+ enum v4l2_buf_type type;
+ struct v4l2_rect c;
+};
+
+/*
+ * A N A L O G V I D E O S T A N D A R D
+ */
+
+typedef unsigned long long v4l2_std_id;
+
+/* one bit for each */
+#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001)
+#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002)
+#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004)
+#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008)
+#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010)
+#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020)
+#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040)
+#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080)
+
+#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100)
+#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200)
+#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400)
+#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800)
+
+#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000)
+#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000)
+
+#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000)
+#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000)
+#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000)
+#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000)
+#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000)
+#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000)
+#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000)
+
+/* ATSC/HDTV */
+#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
+#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
+
+/* some common needed stuff */
+#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\
+ V4L2_STD_PAL_B1 |\
+ V4L2_STD_PAL_G)
+#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\
+ V4L2_STD_PAL_D1 |\
+ V4L2_STD_PAL_K)
+#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\
+ V4L2_STD_PAL_DK |\
+ V4L2_STD_PAL_H |\
+ V4L2_STD_PAL_I)
+#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\
+ V4L2_STD_NTSC_M_JP)
+#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\
+ V4L2_STD_SECAM_D |\
+ V4L2_STD_SECAM_G |\
+ V4L2_STD_SECAM_H |\
+ V4L2_STD_SECAM_K |\
+ V4L2_STD_SECAM_K1 |\
+ V4L2_STD_SECAM_L)
+
+#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\
+ V4L2_STD_PAL_60 |\
+ V4L2_STD_NTSC)
+#define V4L2_STD_625_50 (V4L2_STD_PAL |\
+ V4L2_STD_PAL_N |\
+ V4L2_STD_PAL_Nc |\
+ V4L2_STD_SECAM)
+
+#define V4L2_STD_UNKNOWN 0
+#define V4L2_STD_ALL (V4L2_STD_525_60 |\
+ V4L2_STD_625_50)
+
+struct v4l2_standard
+{
+ __u32 index;
+ v4l2_std_id id;
+ __u8 name[24];
+ struct v4l2_fract frameperiod; /* Frames, not fields */
+ __u32 framelines;
+ __u32 reserved[4];
+};
+
+
+/*
+ * V I D E O I N P U T S
+ */
+struct v4l2_input
+{
+ __u32 index; /* Which input */
+ __u8 name[32]; /* Label */
+ __u32 type; /* Type of input */
+ __u32 audioset; /* Associated audios (bitfield) */
+ __u32 tuner; /* Associated tuner */
+ v4l2_std_id std;
+ __u32 status;
+ __u32 reserved[4];
+};
+/* Values for the 'type' field */
+#define V4L2_INPUT_TYPE_TUNER 1
+#define V4L2_INPUT_TYPE_CAMERA 2
+
+/* field 'status' - general */
+#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */
+#define V4L2_IN_ST_NO_SIGNAL 0x00000002
+#define V4L2_IN_ST_NO_COLOR 0x00000004
+
+/* field 'status' - analog */
+#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */
+#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */
+
+/* field 'status' - digital */
+#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */
+#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */
+#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */
+
+/* field 'status' - VCR and set-top box */
+#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */
+#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */
+#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */
+
+/*
+ * V I D E O O U T P U T S
+ */
+struct v4l2_output
+{
+ __u32 index; /* Which output */
+ __u8 name[32]; /* Label */
+ __u32 type; /* Type of output */
+ __u32 audioset; /* Associated audios (bitfield) */
+ __u32 modulator; /* Associated modulator */
+ v4l2_std_id std;
+ __u32 reserved[4];
+};
+/* Values for the 'type' field */
+#define V4L2_OUTPUT_TYPE_MODULATOR 1
+#define V4L2_OUTPUT_TYPE_ANALOG 2
+#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3
+
+/*
+ * C O N T R O L S
+ */
+struct v4l2_control
+{
+ __u32 id;
+ __s32 value;
+};
+
+/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
+struct v4l2_queryctrl
+{
+ __u32 id;
+ enum v4l2_ctrl_type type;
+ __u8 name[32]; /* Whatever */
+ __s32 minimum; /* Note signedness */
+ __s32 maximum;
+ __s32 step;
+ __s32 default_value;
+ __u32 flags;
+ __u32 reserved[2];
+};
+
+/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
+struct v4l2_querymenu
+{
+ __u32 id;
+ __u32 index;
+ __u8 name[32]; /* Whatever */
+ __u32 reserved;
+};
+
+/* Control flags */
+#define V4L2_CTRL_FLAG_DISABLED 0x0001
+#define V4L2_CTRL_FLAG_GRABBED 0x0002
+
+/* Control IDs defined by V4L2 */
+#define V4L2_CID_BASE 0x00980900
+/* IDs reserved for driver specific controls */
+#define V4L2_CID_PRIVATE_BASE 0x08000000
+
+#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
+#define V4L2_CID_HUE (V4L2_CID_BASE+3)
+#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5)
+#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6)
+#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7)
+#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8)
+#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9)
+#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10)
+#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11)
+#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12)
+#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13)
+#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14)
+#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15)
+#define V4L2_CID_GAMMA (V4L2_CID_BASE+16)
+#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */
+#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17)
+#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18)
+#define V4L2_CID_GAIN (V4L2_CID_BASE+19)
+#define V4L2_CID_HFLIP (V4L2_CID_BASE+20)
+#define V4L2_CID_VFLIP (V4L2_CID_BASE+21)
+#define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
+#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */
+
+/*
+ * T U N I N G
+ */
+struct v4l2_tuner
+{
+ __u32 index;
+ __u8 name[32];
+ enum v4l2_tuner_type type;
+ __u32 capability;
+ __u32 rangelow;
+ __u32 rangehigh;
+ __u32 rxsubchans;
+ __u32 audmode;
+ __s32 signal;
+ __s32 afc;
+ __u32 reserved[4];
+};
+
+struct v4l2_modulator
+{
+ __u32 index;
+ __u8 name[32];
+ __u32 capability;
+ __u32 rangelow;
+ __u32 rangehigh;
+ __u32 txsubchans;
+ __u32 reserved[4];
+};
+
+/* Flags for the 'capability' field */
+#define V4L2_TUNER_CAP_LOW 0x0001
+#define V4L2_TUNER_CAP_NORM 0x0002
+#define V4L2_TUNER_CAP_STEREO 0x0010
+#define V4L2_TUNER_CAP_LANG2 0x0020
+#define V4L2_TUNER_CAP_SAP 0x0020
+#define V4L2_TUNER_CAP_LANG1 0x0040
+
+/* Flags for the 'rxsubchans' field */
+#define V4L2_TUNER_SUB_MONO 0x0001
+#define V4L2_TUNER_SUB_STEREO 0x0002
+#define V4L2_TUNER_SUB_LANG2 0x0004
+#define V4L2_TUNER_SUB_SAP 0x0004
+#define V4L2_TUNER_SUB_LANG1 0x0008
+
+/* Values for the 'audmode' field */
+#define V4L2_TUNER_MODE_MONO 0x0000
+#define V4L2_TUNER_MODE_STEREO 0x0001
+#define V4L2_TUNER_MODE_LANG2 0x0002
+#define V4L2_TUNER_MODE_SAP 0x0002
+#define V4L2_TUNER_MODE_LANG1 0x0003
+
+struct v4l2_frequency
+{
+ __u32 tuner;
+ enum v4l2_tuner_type type;
+ __u32 frequency;
+ __u32 reserved[8];
+};
+
+/*
+ * A U D I O
+ */
+struct v4l2_audio
+{
+ __u32 index;
+ __u8 name[32];
+ __u32 capability;
+ __u32 mode;
+ __u32 reserved[2];
+};
+/* Flags for the 'capability' field */
+#define V4L2_AUDCAP_STEREO 0x00001
+#define V4L2_AUDCAP_AVL 0x00002
+
+/* Flags for the 'mode' field */
+#define V4L2_AUDMODE_AVL 0x00001
+
+struct v4l2_audioout
+{
+ __u32 index;
+ __u8 name[32];
+ __u32 capability;
+ __u32 mode;
+ __u32 reserved[2];
+};
+
+/*
+ * D A T A S E R V I C E S ( V B I )
+ *
+ * Data services API by Michael Schimek
+ */
+
+struct v4l2_vbi_format
+{
+ __u32 sampling_rate; /* in 1 Hz */
+ __u32 offset;
+ __u32 samples_per_line;
+ __u32 sample_format; /* V4L2_PIX_FMT_* */
+ __s32 start[2];
+ __u32 count[2];
+ __u32 flags; /* V4L2_VBI_* */
+ __u32 reserved[2]; /* must be zero */
+};
+
+/* VBI flags */
+#define V4L2_VBI_UNSYNC (1<< 0)
+#define V4L2_VBI_INTERLACED (1<< 1)
+
+
+/*
+ * A G G R E G A T E S T R U C T U R E S
+ */
+
+/* Stream data format
+ */
+struct v4l2_format
+{
+ enum v4l2_buf_type type;
+ union
+ {
+ struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE
+ struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY
+ struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE
+ __u8 raw_data[200]; // user-defined
+ } fmt;
+};
+
+
+/* Stream type-dependent parameters
+ */
+struct v4l2_streamparm
+{
+ enum v4l2_buf_type type;
+ union
+ {
+ struct v4l2_captureparm capture;
+ struct v4l2_outputparm output;
+ __u8 raw_data[200]; /* user-defined */
+ } parm;
+};
+
+
+
+/*
+ * I O C T L C O D E S F O R V I D E O D E V I C E S
+ *
+ */
+#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability)
+#define VIDIOC_RESERVED _IO ('V', 1)
+#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc)
+#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format)
+#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format)
+#if 0
+#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression)
+#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression)
+#endif
+#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers)
+#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer)
+#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer)
+#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer)
+#define VIDIOC_OVERLAY _IOW ('V', 14, int)
+#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer)
+#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer)
+#define VIDIOC_STREAMON _IOW ('V', 18, int)
+#define VIDIOC_STREAMOFF _IOW ('V', 19, int)
+#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm)
+#define VIDIOC_S_PARM _IOWR ('V', 22, struct v4l2_streamparm)
+#define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id)
+#define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id)
+#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard)
+#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input)
+#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control)
+#define VIDIOC_S_CTRL _IOWR ('V', 28, struct v4l2_control)
+#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner)
+#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner)
+#define VIDIOC_G_AUDIO _IOR ('V', 33, struct v4l2_audio)
+#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio)
+#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl)
+#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu)
+#define VIDIOC_G_INPUT _IOR ('V', 38, int)
+#define VIDIOC_S_INPUT _IOWR ('V', 39, int)
+#define VIDIOC_G_OUTPUT _IOR ('V', 46, int)
+#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int)
+#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output)
+#define VIDIOC_G_AUDOUT _IOR ('V', 49, struct v4l2_audioout)
+#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout)
+#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator)
+#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator)
+#define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency)
+#define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency)
+#define VIDIOC_CROPCAP _IOR ('V', 58, struct v4l2_cropcap)
+#define VIDIOC_G_CROP _IOWR ('V', 59, struct v4l2_crop)
+#define VIDIOC_S_CROP _IOW ('V', 60, struct v4l2_crop)
+#define VIDIOC_G_JPEGCOMP _IOR ('V', 61, struct v4l2_jpegcompression)
+#define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression)
+#define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id)
+#define VIDIOC_TRY_FMT _IOWR ('V', 64, struct v4l2_format)
+#define VIDIOC_ENUMAUDIO _IOWR ('V', 65, struct v4l2_audio)
+#define VIDIOC_ENUMAUDOUT _IOWR ('V', 66, struct v4l2_audioout)
+#define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority)
+#define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority)
+
+/* for compatibility, will go away some day */
+#define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int)
+#define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm)
+#define VIDIOC_S_CTRL_OLD _IOW ('V', 28, struct v4l2_control)
+#define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio)
+#define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout)
+
+#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
+
+
+#ifdef __KERNEL__
+/*
+ *
+ * V 4 L 2 D R I V E R H E L P E R A P I
+ *
+ * Some commonly needed functions for drivers (v4l2-common.o module)
+ */
+#include <linux/fs.h>
+
+/* Video standard functions */
+extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
+extern int v4l2_video_std_construct(struct v4l2_standard *vs,
+ int id, char *name);
+
+/* prority handling */
+struct v4l2_prio_state {
+ atomic_t prios[4];
+};
+int v4l2_prio_init(struct v4l2_prio_state *global);
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+ enum v4l2_priority new);
+int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
+int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
+
+/* names for fancy debug output */
+extern char *v4l2_field_names[];
+extern char *v4l2_type_names[];
+extern char *v4l2_ioctl_names[];
+
+/* Compatibility layer interface -- v4l1-compat module */
+typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
+int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
+ int cmd, void *arg, v4l2_kioctl driver_ioctl);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_VIDEODEV2_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/kradio3/plugins/v4lradio/po/Makefile.am b/kradio3/plugins/v4lradio/po/Makefile.am
new file mode 100644
index 0000000..6f04af2
--- /dev/null
+++ b/kradio3/plugins/v4lradio/po/Makefile.am
@@ -0,0 +1,3 @@
+
+PACKAGE = kradio-v4lradio
+POFILES = AUTO
diff --git a/kradio3/plugins/v4lradio/po/de.po b/kradio3/plugins/v4lradio/po/de.po
new file mode 100644
index 0000000..718cb19
--- /dev/null
+++ b/kradio3/plugins/v4lradio/po/de.po
@@ -0,0 +1,362 @@
+# translation of de.po to
+# translation of kradio-v4lradio.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-06 00:24+0100\n"
+"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n"
+"Language-Team: <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. i18n: file v4lradio-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:90 v4lradio-configuration-ui.cpp:328
+#, no-c-format
+msgid "SetupDialogGeneral"
+msgstr "SetupDialogGeneral"
+
+#. i18n: file v4lradio-configuration-ui.ui line 37
+#: rc.cpp:6 rc.cpp:93 v4lradio-configuration-ui.cpp:344
+#, no-c-format
+msgid "Devices"
+msgstr "Geräte"
+
+#. i18n: file v4lradio-configuration-ui.ui line 68
+#: rc.cpp:9 rc.cpp:96 v4lradio-configuration-ui.cpp:329
+#, no-c-format
+msgid "Playback Mixer Device"
+msgstr "Wiedergabe Mixer"
+
+#. i18n: file v4lradio-configuration-ui.ui line 76
+#: rc.cpp:12 rc.cpp:99 v4lradio-configuration-ui.cpp:330
+#, no-c-format
+msgid "Playback Mixer Channel"
+msgstr "Wiedergabe Mixerkanal"
+
+#. i18n: file v4lradio-configuration-ui.ui line 169
+#: rc.cpp:15 rc.cpp:102 v4lradio-configuration-ui.cpp:331
+#, no-c-format
+msgid "Radio Device"
+msgstr "Radio Gerät"
+
+#. i18n: file v4lradio-configuration-ui.ui line 196
+#: rc.cpp:19 rc.cpp:106 v4lradio-configuration-ui.cpp:333
+#, no-c-format
+msgid "Capture Mixer Device"
+msgstr "Aufnahme Mixer"
+
+#. i18n: file v4lradio-configuration-ui.ui line 217
+#: rc.cpp:22 rc.cpp:109 v4lradio-configuration-ui.cpp:334
+#, no-c-format
+msgid "Capture Mixer Channel"
+msgstr "Aufnahme Mixerkanal"
+
+#. i18n: file v4lradio-configuration-ui.ui line 249
+#: rc.cpp:25 rc.cpp:112 v4lradio-configuration-ui.cpp:336
+#, no-c-format
+msgid "test"
+msgstr "test"
+
+#. i18n: file v4lradio-configuration-ui.ui line 269
+#: rc.cpp:28 rc.cpp:115 v4lradio-configuration-ui.cpp:337
+#, no-c-format
+msgid "unknown v4l device"
+msgstr "Unbekanntes V4L-Gerät"
+
+#. i18n: file v4lradio-configuration-ui.ui line 315
+#: rc.cpp:31 rc.cpp:118 v4lradio-configuration-ui.cpp:338
+#, no-c-format
+msgid "Use active pla&yback by capturing"
+msgstr "Aktive &Wiedergabe verwenden (Aufgenommenes abspielen)"
+
+#. i18n: file v4lradio-configuration-ui.ui line 318
+#: rc.cpp:34 rc.cpp:121 v4lradio-configuration-ui.cpp:339
+#, no-c-format
+msgid "Alt+Y"
+msgstr "Alt+Y"
+
+#. i18n: file v4lradio-configuration-ui.ui line 334
+#: rc.cpp:37 rc.cpp:124 v4lradio-configuration-ui.cpp:340
+#, no-c-format
+msgid "Mute Play&back Channel on Power Off"
+msgstr "Wiedergabekanal beim Abschalten des Radios stummschalten"
+
+#. i18n: file v4lradio-configuration-ui.ui line 337
+#: rc.cpp:40 rc.cpp:127 v4lradio-configuration-ui.cpp:341
+#, no-c-format
+msgid "Alt+B"
+msgstr "Alt+B"
+
+#. i18n: file v4lradio-configuration-ui.ui line 353
+#: rc.cpp:43 rc.cpp:130 v4lradio-configuration-ui.cpp:342
+#, no-c-format
+msgid "Set Playback Channel Volume to &Zero on Power Off"
+msgstr "Wiedergabelautstärke beim Abschalten des Radios auf 0 setzen"
+
+#. i18n: file v4lradio-configuration-ui.ui line 356
+#: rc.cpp:46 rc.cpp:133 v4lradio-configuration-ui.cpp:343
+#, no-c-format
+msgid "Alt+Z"
+msgstr "Alt+Z"
+
+#. i18n: file v4lradio-configuration-ui.ui line 394
+#: rc.cpp:52 rc.cpp:139 v4lradio-configuration-ui.cpp:345
+#, no-c-format
+msgid "to"
+msgstr "bis"
+
+#. i18n: file v4lradio-configuration-ui.ui line 413
+#. i18n: file v4lradio-configuration-ui.ui line 443
+#. i18n: file v4lradio-configuration-ui.ui line 479
+#. i18n: file v4lradio-configuration-ui.ui line 413
+#. i18n: file v4lradio-configuration-ui.ui line 443
+#. i18n: file v4lradio-configuration-ui.ui line 479
+#: rc.cpp:55 rc.cpp:58 rc.cpp:64 rc.cpp:142 rc.cpp:145 rc.cpp:151
+#: v4lradio-configuration-ui.cpp:346 v4lradio-configuration-ui.cpp:347
+#: v4lradio-configuration-ui.cpp:349
+#, no-c-format
+msgid " kHz"
+msgstr " kHz"
+
+#. i18n: file v4lradio-configuration-ui.ui line 460
+#: rc.cpp:61 rc.cpp:148 v4lradio-configuration-ui.cpp:348
+#, no-c-format
+msgid "minimum signal quality"
+msgstr "Mindest-Signalpegel"
+
+#. i18n: file v4lradio-configuration-ui.ui line 499
+#: rc.cpp:67 rc.cpp:154 v4lradio-configuration-ui.cpp:350
+#, no-c-format
+msgid "station scan step"
+msgstr "Sendersuchschrittweite"
+
+#. i18n: file v4lradio-configuration-ui.ui line 507
+#: rc.cpp:70 rc.cpp:157 v4lradio-configuration-ui.cpp:351
+#, no-c-format
+msgid "allowed frequency range"
+msgstr "erlaubter Frequenzbereich"
+
+#. i18n: file v4lradio-configuration-ui.ui line 566
+#: rc.cpp:75 rc.cpp:162 v4lradio-configuration-ui.cpp:359
+#, no-c-format
+msgid "V4L Mixer Controls"
+msgstr "V4L Mixersteuerung"
+
+#. i18n: file v4lradio-configuration-ui.ui line 594
+#: rc.cpp:78 rc.cpp:165 v4lradio-configuration-ui.cpp:355
+#, no-c-format
+msgid "volume"
+msgstr "Lautstärke"
+
+#. i18n: file v4lradio-configuration-ui.ui line 684
+#: rc.cpp:81 rc.cpp:168 v4lradio-configuration-ui.cpp:356
+#, no-c-format
+msgid "treble"
+msgstr "Höhen"
+
+#. i18n: file v4lradio-configuration-ui.ui line 774
+#: rc.cpp:84 rc.cpp:171 v4lradio-configuration-ui.cpp:357
+#, no-c-format
+msgid "bass"
+msgstr "Tiefen"
+
+#. i18n: file v4lradio-configuration-ui.ui line 861
+#: rc.cpp:87 rc.cpp:174 v4lradio-configuration-ui.cpp:358
+#, no-c-format
+msgid "balance"
+msgstr "Balance"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: v4lradio-configuration.cpp:443
+msgid "any ( * )"
+msgstr "Alle ( * )"
+
+#: v4lradio-configuration.cpp:445
+msgid "Radio Device Selection"
+msgstr "Auswahl der Radio-Gerätedatei"
+
+#: v4lradio-configuration.cpp:448
+msgid "Select Radio Device"
+msgstr "Wählen Sie die Radio-Gerätedatei aus"
+
+#: v4lradio.cpp:56
+msgid "Support for V4L(2) Radio Devices"
+msgstr "Unterstützung für V4L(2)-Radiogeräte"
+
+#: v4lradio.cpp:61
+msgid "Video For Linux Plugin"
+msgstr "Video für Linux (V4L) Plugin"
+
+#: v4lradio.cpp:659
+msgid "invalid frequency %1"
+msgstr "ungültige Frequenz: %1"
+
+#: v4lradio.cpp:680 v4lradio.cpp:1358 v4lradio.cpp:1507
+msgid "don't known how to handle V4L-version %1"
+msgstr "Keine Ahnung, wie die V4L-Version %1 behandelt werden soll"
+
+#: v4lradio.cpp:686
+msgid "error setting frequency to %1 (%2)"
+msgstr "Fehler (%2) beim Einstellen der Frequenz auf %1."
+
+#: v4lradio.cpp:1004
+msgid ""
+"Device %1 does exist but is not readable/writable. Please check device "
+"permissions."
+msgstr ""
+"Das Gerät %1 existiert, ist aber nicht lesbar/schreibbar. Bitte überprüfen "
+"Sie die Einstellung der Zugriffsrechte für das Gerät."
+
+#: v4lradio.cpp:1014
+msgid "Could not find an accessible v4l(2) radio device."
+msgstr "Kann kein verwendbares V4L(2)-Radiogerät finden."
+
+#: v4lradio.cpp:1077
+msgid "V4L Radio"
+msgstr "V4L Radio"
+
+#: v4lradio.cpp:1078
+msgid "V4L Radio Options"
+msgstr "Optionen des V4L-Radios"
+
+#: v4lradio.cpp:1088
+msgid ""
+"V4L/V4L2 Plugin for KRadio.<P>Provides Support for V4L/V4L2 based Radio "
+"Cards<P>"
+msgstr ""
+"V4L/V4L2-Plugin für KRadio.<P>Dieses Plugin bindet vom V4L/V4L2-Treiber "
+"unterstützte Radio-Karten in KRadio ein.<P>"
+
+#: v4lradio.cpp:1103
+msgid "V4L/V4L2"
+msgstr "V4L/V4L2"
+
+#: v4lradio.cpp:1104
+msgid "V4L/V4L2 Plugin"
+msgstr "V4L/V4L2-Plugin"
+
+#: v4lradio.cpp:1135
+msgid "Cannot open radio device %1"
+msgstr "Die Radiogerätedatei %1 kann nicht geöffnet werden"
+
+#: v4lradio.cpp:1186
+msgid "cannot open %1"
+msgstr "%1 kann nicht geöffnet werden"
+
+#: v4lradio.cpp:1210
+msgid "audio caps = %1"
+msgstr "Audio-Fähigkeiten: %1"
+
+#: v4lradio.cpp:1224
+msgid "error reading V4L1 caps"
+msgstr "Fehler beim Lesen der V4L1-Fähigkeiten"
+
+#: v4lradio.cpp:1233
+msgid "V4L2 - Version: %1"
+msgstr "V4L2 - Version: %1"
+
+#: v4lradio.cpp:1253
+msgid "V4L2: Querying mute control failed"
+msgstr "V4L2: Die Abfrage des Stummschaltungs-Reglers schlug fehl"
+
+#: v4lradio.cpp:1260
+msgid "V4L2: Querying volume control failed"
+msgstr "V4L2: Die Abfrage des Lautstärke-Reglers schlug fehl"
+
+#: v4lradio.cpp:1268
+msgid "V4L2: Querying treble control failed"
+msgstr "V4L2: Die Abfrage des Höhen-Reglers schlug fehl"
+
+#: v4lradio.cpp:1276
+msgid "V4L2: Querying bass control failed"
+msgstr "V4L2: Die Abfrage des Bass-Reglers schlug fehl"
+
+#: v4lradio.cpp:1284
+msgid "V4L2: Querying balance control failed"
+msgstr "V4L2: Die Abfrage des Balance-Reglers schlug fehl"
+
+#: v4lradio.cpp:1288
+msgid "V4LRadio::readV4LCaps: Reading V4L2 caps failed"
+msgstr "V4LRadio::readV4LCaps: Das Lesen der V4L2-Fähigkeiten schlug fehl"
+
+#: v4lradio.cpp:1292
+msgid "V4L %1 detected"
+msgstr "V4L %1 wurde gefunden"
+
+#: v4lradio.cpp:1294
+msgid "V4L not detected"
+msgstr "Das Radiogerät unterstützt V4L nicht"
+
+#: v4lradio.cpp:1297
+msgid "Radio is mutable"
+msgstr "Das Radio kann stummgeschaltet werden"
+
+#: v4lradio.cpp:1297
+msgid "Radio is not mutable"
+msgstr "Das Radio kann nicht stummgeschaltet werden"
+
+#: v4lradio.cpp:1298
+msgid "Radio has Volume Control"
+msgstr "Das Radio hat einen Lautstärkeregler"
+
+#: v4lradio.cpp:1298
+msgid "Radio has no Volume Control"
+msgstr "Das Radio hat keinen Lautstärkeregler"
+
+#: v4lradio.cpp:1299
+msgid "Radio has Bass Control"
+msgstr "Das Radio hat einen Bass-Regler"
+
+#: v4lradio.cpp:1299
+msgid "Radio has no Bass Control"
+msgstr "Das Radio hat keinen Bass-Regler"
+
+#: v4lradio.cpp:1300
+msgid "Radio has Treble Control"
+msgstr "Das Radio hat einen Höhen-Regler"
+
+#: v4lradio.cpp:1300
+msgid "Radio has no Treble Control"
+msgstr "Das Radio hat keinen Bass-Regler"
+
+#: v4lradio.cpp:1365
+msgid "cannot get tuner info (error %1)"
+msgstr "Tuner-Informationen können nicht gelesen werden (Fehler %1)"
+
+#: v4lradio.cpp:1409
+msgid "error setting %1: %2"
+msgstr "Fehler %2 beim Setzen von %1"
+
+#: v4lradio.cpp:1417
+msgid "error reading %1: %2"
+msgstr "Fehler %2 beim Lesen von %1"
+
+#: v4lradio.cpp:1513
+msgid "error updating radio audio info (%1): %2"
+msgstr "Fehler %2 beim Updaten der Audio-Informationen (%1)"
+
+#: v4lradio.cpp:1514
+msgid "write"
+msgstr "Schreiben"
+
+#: v4lradio.cpp:1514
+msgid "read"
+msgstr "Lesen"
diff --git a/kradio3/plugins/v4lradio/po/ru.po b/kradio3/plugins/v4lradio/po/ru.po
new file mode 100644
index 0000000..dc57522
--- /dev/null
+++ b/kradio3/plugins/v4lradio/po/ru.po
@@ -0,0 +1,362 @@
+# translation of ru.po to
+# translation of kradio-v4lradio.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-11-11 18:43+0100\n"
+"PO-Revision-Date: 2006-11-08 11:59+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. i18n: file v4lradio-configuration-ui.ui line 16
+#: rc.cpp:3 rc.cpp:90 v4lradio-configuration-ui.cpp:328
+#, no-c-format
+msgid "SetupDialogGeneral"
+msgstr "SetupDialogGeneral"
+
+#. i18n: file v4lradio-configuration-ui.ui line 37
+#: rc.cpp:6 rc.cpp:93 v4lradio-configuration-ui.cpp:344
+#, no-c-format
+msgid "Devices"
+msgstr "Устройства"
+
+#. i18n: file v4lradio-configuration-ui.ui line 68
+#: rc.cpp:9 rc.cpp:96 v4lradio-configuration-ui.cpp:329
+#, no-c-format
+msgid "Playback Mixer Device"
+msgstr "Устройство воспроизведения"
+
+#. i18n: file v4lradio-configuration-ui.ui line 76
+#: rc.cpp:12 rc.cpp:99 v4lradio-configuration-ui.cpp:330
+#, no-c-format
+msgid "Playback Mixer Channel"
+msgstr "Канал воспроизведения"
+
+#. i18n: file v4lradio-configuration-ui.ui line 169
+#: rc.cpp:15 rc.cpp:102 v4lradio-configuration-ui.cpp:331
+#, no-c-format
+msgid "Radio Device"
+msgstr "Устройство радио"
+
+#. i18n: file v4lradio-configuration-ui.ui line 196
+#: rc.cpp:19 rc.cpp:106 v4lradio-configuration-ui.cpp:333
+#, no-c-format
+msgid "Capture Mixer Device"
+msgstr "Устройство записи"
+
+#. i18n: file v4lradio-configuration-ui.ui line 217
+#: rc.cpp:22 rc.cpp:109 v4lradio-configuration-ui.cpp:334
+#, no-c-format
+msgid "Capture Mixer Channel"
+msgstr "Канал записи"
+
+#. i18n: file v4lradio-configuration-ui.ui line 249
+#: rc.cpp:25 rc.cpp:112 v4lradio-configuration-ui.cpp:336
+#, no-c-format
+msgid "test"
+msgstr "проверка"
+
+#. i18n: file v4lradio-configuration-ui.ui line 269
+#: rc.cpp:28 rc.cpp:115 v4lradio-configuration-ui.cpp:337
+#, no-c-format
+msgid "unknown v4l device"
+msgstr "неизвестно"
+
+#. i18n: file v4lradio-configuration-ui.ui line 315
+#: rc.cpp:31 rc.cpp:118 v4lradio-configuration-ui.cpp:338
+#, no-c-format
+msgid "Use active pla&yback by capturing"
+msgstr "Захватывать звук и затем проигрывать его"
+
+#. i18n: file v4lradio-configuration-ui.ui line 318
+#: rc.cpp:34 rc.cpp:121 v4lradio-configuration-ui.cpp:339
+#, no-c-format
+msgid "Alt+Y"
+msgstr "Alt+Y"
+
+#. i18n: file v4lradio-configuration-ui.ui line 334
+#: rc.cpp:37 rc.cpp:124 v4lradio-configuration-ui.cpp:340
+#, no-c-format
+msgid "Mute Play&back Channel on Power Off"
+msgstr "Выключать звук на канале воспроизведения при выходе"
+
+#. i18n: file v4lradio-configuration-ui.ui line 337
+#: rc.cpp:40 rc.cpp:127 v4lradio-configuration-ui.cpp:341
+#, no-c-format
+msgid "Alt+B"
+msgstr "Alt+B"
+
+#. i18n: file v4lradio-configuration-ui.ui line 353
+#: rc.cpp:43 rc.cpp:130 v4lradio-configuration-ui.cpp:342
+#, no-c-format
+msgid "Set Playback Channel Volume to &Zero on Power Off"
+msgstr "Устанавливать &нулевую громкость воспроизведения при выходе"
+
+#. i18n: file v4lradio-configuration-ui.ui line 356
+#: rc.cpp:46 rc.cpp:133 v4lradio-configuration-ui.cpp:343
+#, no-c-format
+msgid "Alt+Z"
+msgstr "Alt+Z"
+
+#. i18n: file v4lradio-configuration-ui.ui line 394
+#: rc.cpp:52 rc.cpp:139 v4lradio-configuration-ui.cpp:345
+#, no-c-format
+msgid "to"
+msgstr "до"
+
+#. i18n: file v4lradio-configuration-ui.ui line 413
+#. i18n: file v4lradio-configuration-ui.ui line 443
+#. i18n: file v4lradio-configuration-ui.ui line 479
+#. i18n: file v4lradio-configuration-ui.ui line 413
+#. i18n: file v4lradio-configuration-ui.ui line 443
+#. i18n: file v4lradio-configuration-ui.ui line 479
+#: rc.cpp:55 rc.cpp:58 rc.cpp:64 rc.cpp:142 rc.cpp:145 rc.cpp:151
+#: v4lradio-configuration-ui.cpp:346 v4lradio-configuration-ui.cpp:347
+#: v4lradio-configuration-ui.cpp:349
+#, no-c-format
+msgid " kHz"
+msgstr " кГц"
+
+#. i18n: file v4lradio-configuration-ui.ui line 460
+#: rc.cpp:61 rc.cpp:148 v4lradio-configuration-ui.cpp:348
+#, no-c-format
+msgid "minimum signal quality"
+msgstr "Минимальный уровень сигнала"
+
+#. i18n: file v4lradio-configuration-ui.ui line 499
+#: rc.cpp:67 rc.cpp:154 v4lradio-configuration-ui.cpp:350
+#, no-c-format
+msgid "station scan step"
+msgstr "Шаг изменения частоты при поиске"
+
+#. i18n: file v4lradio-configuration-ui.ui line 507
+#: rc.cpp:70 rc.cpp:157 v4lradio-configuration-ui.cpp:351
+#, no-c-format
+msgid "allowed frequency range"
+msgstr "Допустимый частотный диапазон:\tот"
+
+#. i18n: file v4lradio-configuration-ui.ui line 566
+#: rc.cpp:75 rc.cpp:162 v4lradio-configuration-ui.cpp:359
+#, no-c-format
+msgid "V4L Mixer Controls"
+msgstr "Аппаратные регуляторы V4l"
+
+#. i18n: file v4lradio-configuration-ui.ui line 594
+#: rc.cpp:78 rc.cpp:165 v4lradio-configuration-ui.cpp:355
+#, no-c-format
+msgid "volume"
+msgstr "Громкость"
+
+#. i18n: file v4lradio-configuration-ui.ui line 684
+#: rc.cpp:81 rc.cpp:168 v4lradio-configuration-ui.cpp:356
+#, no-c-format
+msgid "treble"
+msgstr "ВЧ"
+
+#. i18n: file v4lradio-configuration-ui.ui line 774
+#: rc.cpp:84 rc.cpp:171 v4lradio-configuration-ui.cpp:357
+#, no-c-format
+msgid "bass"
+msgstr "НЧ"
+
+#. i18n: file v4lradio-configuration-ui.ui line 861
+#: rc.cpp:87 rc.cpp:174 v4lradio-configuration-ui.cpp:358
+#, no-c-format
+msgid "balance"
+msgstr "Стереобаланс"
+
+#: _translatorinfo.cpp:1
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#: _translatorinfo.cpp:3
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: v4lradio-configuration.cpp:443
+msgid "any ( * )"
+msgstr "Все ( * )"
+
+#: v4lradio-configuration.cpp:445
+msgid "Radio Device Selection"
+msgstr "Выбор устройства радио"
+
+#: v4lradio-configuration.cpp:448
+msgid "Select Radio Device"
+msgstr "Выберите устройство радиоприёмника"
+
+#: v4lradio.cpp:56
+msgid "Support for V4L(2) Radio Devices"
+msgstr "Поддержка устройств V4l(2)"
+
+#: v4lradio.cpp:61
+msgid "Video For Linux Plugin"
+msgstr "Модуль \"Видео для linux\""
+
+#: v4lradio.cpp:659
+msgid "invalid frequency %1"
+msgstr "Неправильная частота %1"
+
+#: v4lradio.cpp:680 v4lradio.cpp:1358 v4lradio.cpp:1507
+msgid "don't known how to handle V4L-version %1"
+msgstr "Не знаю что делать с версией V4l \"%1\""
+
+#: v4lradio.cpp:686
+msgid "error setting frequency to %1 (%2)"
+msgstr "Ошибка установки частоты %1 (%2)"
+
+#: v4lradio.cpp:1004
+msgid ""
+"Device %1 does exist but is not readable/writable. Please check device "
+"permissions."
+msgstr ""
+"Устройство %1 недоступно для чтения/записи. Проверьте права на устройство, а "
+"также не использует ли его другая программа."
+
+#: v4lradio.cpp:1014
+msgid "Could not find an accessible v4l(2) radio device."
+msgstr "Не найти доступное устройство V4l(2)."
+
+#: v4lradio.cpp:1077
+msgid "V4L Radio"
+msgstr "Радио V4l"
+
+#: v4lradio.cpp:1078
+msgid "V4L Radio Options"
+msgstr "Параметры устройства V4l"
+
+#: v4lradio.cpp:1088
+msgid ""
+"V4L/V4L2 Plugin for KRadio.<P>Provides Support for V4L/V4L2 based Radio "
+"Cards<P>"
+msgstr ""
+"Модуль V4l/V4l2 для KRadio. <P> Предоставляет поддержку плат радио, "
+"совместимых с V4l/V4l2<P>"
+
+#: v4lradio.cpp:1103
+msgid "V4L/V4L2"
+msgstr "V4L/V4LV2"
+
+#: v4lradio.cpp:1104
+msgid "V4L/V4L2 Plugin"
+msgstr "Модуль V4L/V4L2"
+
+#: v4lradio.cpp:1135
+msgid "Cannot open radio device %1"
+msgstr "Не могу открыть устройство радио: %1"
+
+#: v4lradio.cpp:1186
+msgid "cannot open %1"
+msgstr "Не могу открыть %1"
+
+#: v4lradio.cpp:1210
+msgid "audio caps = %1"
+msgstr "возможности звука = %1"
+
+#: v4lradio.cpp:1224
+msgid "error reading V4L1 caps"
+msgstr "Ошибка чтения возможностей V4l1"
+
+#: v4lradio.cpp:1233
+msgid "V4L2 - Version: %1"
+msgstr "Версия V4l2: %1"
+
+#: v4lradio.cpp:1253
+msgid "V4L2: Querying mute control failed"
+msgstr "V4L2: Не могу обратиться к выключателю звука платы"
+
+#: v4lradio.cpp:1260
+msgid "V4L2: Querying volume control failed"
+msgstr "V4L2: Не могу обратиться к регулятору громкости"
+
+#: v4lradio.cpp:1268
+msgid "V4L2: Querying treble control failed"
+msgstr "V4L2: Не могу обратиться к регулятору верхних частот"
+
+#: v4lradio.cpp:1276
+msgid "V4L2: Querying bass control failed"
+msgstr "V4L2: Не могу обратиться к регулятору нижних частот"
+
+#: v4lradio.cpp:1284
+msgid "V4L2: Querying balance control failed"
+msgstr "V4L2: Не могу обратиться к регулятору стереобаланса"
+
+#: v4lradio.cpp:1288
+msgid "V4LRadio::readV4LCaps: Reading V4L2 caps failed"
+msgstr "V4LRadio::readV4LCaps:Не могу узнать возможности устройства"
+
+#: v4lradio.cpp:1292
+msgid "V4L %1 detected"
+msgstr "Найдено устройство V4L: %1"
+
+#: v4lradio.cpp:1294
+msgid "V4L not detected"
+msgstr "Устройств V4L не обнаружено"
+
+#: v4lradio.cpp:1297
+msgid "Radio is mutable"
+msgstr "Радио не поддерживает выключения звука"
+
+#: v4lradio.cpp:1297
+msgid "Radio is not mutable"
+msgstr "Радио поддерживает выключение звука"
+
+#: v4lradio.cpp:1298
+msgid "Radio has Volume Control"
+msgstr "Есть регулировка громкости"
+
+#: v4lradio.cpp:1298
+msgid "Radio has no Volume Control"
+msgstr "Регулировки громкости нет"
+
+#: v4lradio.cpp:1299
+msgid "Radio has Bass Control"
+msgstr "Есть регулировка НЧ"
+
+#: v4lradio.cpp:1299
+msgid "Radio has no Bass Control"
+msgstr "Регулировки НЧ нет"
+
+#: v4lradio.cpp:1300
+msgid "Radio has Treble Control"
+msgstr "Есть регулировка ВЧ"
+
+#: v4lradio.cpp:1300
+msgid "Radio has no Treble Control"
+msgstr "Регулировки ВЧ нет"
+
+#: v4lradio.cpp:1365
+msgid "cannot get tuner info (error %1)"
+msgstr "Не могу получить информацию о тюнере (код ошибки %1)"
+
+#: v4lradio.cpp:1409
+msgid "error setting %1: %2"
+msgstr "Ошибка установки %1: %2"
+
+#: v4lradio.cpp:1417
+msgid "error reading %1: %2"
+msgstr "Ошибка чтения %1: %2"
+
+#: v4lradio.cpp:1513
+msgid "error updating radio audio info (%1): %2"
+msgstr "Ошибка %1: %2"
+
+#: v4lradio.cpp:1514
+msgid "write"
+msgstr "запись"
+
+#: v4lradio.cpp:1514
+msgid "read"
+msgstr "чтение"
diff --git a/kradio3/plugins/v4lradio/v4lcfg_interfaces.cpp b/kradio3/plugins/v4lradio/v4lcfg_interfaces.cpp
new file mode 100644
index 0000000..c679c76
--- /dev/null
+++ b/kradio3/plugins/v4lradio/v4lcfg_interfaces.cpp
@@ -0,0 +1,193 @@
+/***************************************************************************
+ v4lradio_interfaces.cpp - description
+ -------------------
+ begin : Sam Jun 21 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 <linux/soundcard.h>
+#include "v4lcfg_interfaces.h"
+
+///////////////////////////////////////////////////////////////////////
+
+V4LCaps::V4LCaps()
+ : version(0),
+ description(QString::null),
+ hasMute(false),
+ hasVolume(false),
+ minVolume(0),
+ maxVolume(65535),
+ hasTreble(false),
+ minTreble(0),
+ maxTreble(65535),
+ hasBass(false),
+ minBass(0),
+ maxBass(65535),
+ hasBalance(false),
+ minBalance(0),
+ maxBalance(65535)
+{
+}
+
+
+V4LCaps::V4LCaps(const V4LCaps &c)
+ : version(c.version),
+ description(c.description),
+ hasMute(c.hasMute),
+ hasVolume(c.hasVolume),
+ minVolume(c.minVolume),
+ maxVolume(c.maxVolume),
+ hasTreble(c.hasTreble),
+ minTreble(c.minTreble),
+ maxTreble(c.maxTreble),
+ hasBass(c.hasBass),
+ minBass(c.minBass),
+ maxBass(c.maxBass),
+ hasBalance(c.hasBalance),
+ minBalance(c.minBalance),
+ maxBalance(c.maxBalance)
+{
+}
+
+
+// IV4LCfg
+
+IF_IMPL_SENDER ( IV4LCfg::notifyRadioDeviceChanged(const QString &s),
+ noticeRadioDeviceChanged(s)
+ )
+IF_IMPL_SENDER ( IV4LCfg::notifyPlaybackMixerChanged(const QString &s, const QString &Channel),
+ noticePlaybackMixerChanged(s, Channel)
+ )
+IF_IMPL_SENDER ( IV4LCfg::notifyCaptureMixerChanged(const QString &s, const QString &Channel),
+ noticeCaptureMixerChanged(s, Channel)
+ )
+IF_IMPL_SENDER ( IV4LCfg::notifyDeviceVolumeChanged(float v),
+ noticeDeviceVolumeChanged(v)
+ )
+IF_IMPL_SENDER ( IV4LCfg::notifyCapabilitiesChanged(const V4LCaps &c),
+ noticeCapabilitiesChanged(c)
+ )
+
+IF_IMPL_SENDER ( IV4LCfg::notifyActivePlaybackChanged(bool a),
+ noticeActivePlaybackChanged(a)
+ )
+
+IF_IMPL_SENDER ( IV4LCfg::notifyMuteOnPowerOffChanged(bool a),
+ noticeMuteOnPowerOffChanged(a)
+ )
+
+IF_IMPL_SENDER ( IV4LCfg::notifyVolumeZeroOnPowerOffChanged(bool a),
+ noticeVolumeZeroOnPowerOffChanged(a)
+ )
+// IV4LCfgClient
+
+IF_IMPL_SENDER ( IV4LCfgClient::sendRadioDevice (const QString &s),
+ setRadioDevice(s)
+ )
+IF_IMPL_SENDER ( IV4LCfgClient::sendPlaybackMixer(const QString &s, const QString &ch),
+ setPlaybackMixer(s, ch)
+ )
+IF_IMPL_SENDER ( IV4LCfgClient::sendCaptureMixer(const QString &s, const QString &ch),
+ setCaptureMixer(s, ch)
+ )
+IF_IMPL_SENDER ( IV4LCfgClient::sendDeviceVolume(float v),
+ setDeviceVolume(v)
+ )
+
+IF_IMPL_SENDER ( IV4LCfgClient::sendActivePlayback(bool a),
+ setActivePlayback(a)
+ )
+
+IF_IMPL_SENDER ( IV4LCfgClient::sendMuteOnPowerOff(bool a),
+ setMuteOnPowerOff(a)
+ )
+
+IF_IMPL_SENDER ( IV4LCfgClient::sendVolumeZeroOnPowerOff(bool a),
+ setVolumeZeroOnPowerOff(a)
+ )
+
+static QString defaultRDev("/dev/radio");
+// static QString defaultMDev("/dev/mixer");
+
+IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryRadioDevice (),
+ getRadioDevice(),
+ defaultRDev
+ )
+IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryPlaybackMixerID (),
+ getPlaybackMixerID(),
+ QString::null
+ )
+IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryCaptureMixerID (),
+ getCaptureMixerID(),
+ QString::null
+ )
+
+static const QString channel_line("Line");
+IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryPlaybackMixerChannel(),
+ getPlaybackMixerChannel(),
+ channel_line
+ )
+IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryCaptureMixerChannel(),
+ getCaptureMixerChannel(),
+ channel_line
+ )
+IF_IMPL_QUERY ( float IV4LCfgClient::queryDeviceVolume (),
+ getDeviceVolume(),
+ 0.0
+ )
+IF_IMPL_QUERY ( V4LCaps IV4LCfgClient::queryCapabilities(QString dev),
+ getCapabilities(dev),
+ V4LCaps()
+ )
+
+IF_IMPL_QUERY ( bool IV4LCfgClient::queryActivePlayback(),
+ getActivePlayback(),
+ false
+ )
+
+IF_IMPL_QUERY ( bool IV4LCfgClient::queryMuteOnPowerOff(),
+ getMuteOnPowerOff(),
+ false
+ )
+
+IF_IMPL_QUERY ( bool IV4LCfgClient::queryVolumeZeroOnPowerOff(),
+ getVolumeZeroOnPowerOff(),
+ false
+ )
+
+void IV4LCfgClient::noticeConnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ noticeRadioDeviceChanged(queryRadioDevice());
+ noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel());
+ noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel());
+ noticeDeviceVolumeChanged(queryDeviceVolume());
+ noticeCapabilitiesChanged(queryCapabilities());
+ noticeActivePlaybackChanged(queryActivePlayback());
+ noticeMuteOnPowerOffChanged(queryMuteOnPowerOff());
+ noticeVolumeZeroOnPowerOffChanged(queryVolumeZeroOnPowerOff());
+}
+
+
+void IV4LCfgClient::noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ noticeRadioDeviceChanged(queryRadioDevice());
+ noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel());
+ noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel());
+ noticeDeviceVolumeChanged(queryDeviceVolume());
+ noticeCapabilitiesChanged(queryCapabilities());
+ noticeActivePlaybackChanged(queryActivePlayback());
+ noticeMuteOnPowerOffChanged(queryMuteOnPowerOff());
+ noticeVolumeZeroOnPowerOffChanged(queryVolumeZeroOnPowerOff());
+}
+
+
diff --git a/kradio3/plugins/v4lradio/v4lcfg_interfaces.h b/kradio3/plugins/v4lradio/v4lcfg_interfaces.h
new file mode 100644
index 0000000..f2e1032
--- /dev/null
+++ b/kradio3/plugins/v4lradio/v4lcfg_interfaces.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+ v4lradio_interfaces.h - description
+ -------------------
+ begin : Sam Jun 21 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_V4LCFG_INTERFACES_H
+#define KRADIO_V4LCFG_INTERFACES_H
+
+#include "../../src/include/interfaces.h"
+#include "math.h"
+
+struct V4LCaps
+{
+ int version;
+ QString description;
+
+ bool hasMute;
+
+ bool hasVolume;
+ int minVolume, maxVolume;
+ bool hasTreble;
+ int minTreble, maxTreble;
+ bool hasBass;
+ int minBass, maxBass;
+ bool hasBalance;
+ int minBalance, maxBalance;
+
+ V4LCaps();
+ V4LCaps(const V4LCaps &);
+
+ float volumeStep() const { return 1.0 / (float)(maxVolume - minVolume); }
+ float trebleStep() const { return 1.0 / (float)(maxTreble - minTreble); }
+ float bassStep() const { return 1.0 / (float)(maxBass - minBass); }
+ float balanceStep() const { return 1.0 / (float)(maxBalance - minBalance); }
+
+ void setVolume (int min, int max) { hasVolume = true; minVolume = min; maxVolume = max; }
+ void setTreble (int min, int max) { hasTreble = true; minTreble = min; maxTreble = max; }
+ void setBass (int min, int max) { hasBass = true; minBass = min; maxBass = max; }
+ void setBalance(int min, int max) { hasBalance = true; minBalance = min; maxBalance = max; }
+
+ void unsetVolume () { hasVolume = false; minVolume = 0; maxVolume = 65535; }
+ void unsetTreble () { hasTreble = false; minTreble = 0; maxTreble = 65535; }
+ void unsetBass () { hasBass = false; minBass = 0; maxBass = 65535; }
+ void unsetBalance() { hasBalance = false; minBalance = 0; maxBalance = 65535; }
+
+ int intGetVolume (float f) const { return (int)rint(minVolume + (maxVolume - minVolume ) * f); }
+ int intGetTreble (float f) const { return (int)rint(minTreble + (maxTreble - minTreble ) * f); }
+ int intGetBass (float f) const { return (int)rint(minBass + (maxBass - minBass ) * f); }
+ int intGetBalance(float f) const { return (int)rint(minBalance + (maxBalance - minBalance) / 2.0 * (1.0 + f)); }
+
+ float floatGetVolume (int i) const { return (float)(i - minVolume) * volumeStep(); }
+ float floatGetTreble (int i) const { return (float)(i - minTreble) * trebleStep(); }
+ float floatGetBass (int i) const { return (float)(i - minBass ) * bassStep(); }
+ float floatGetBalance(int i) const { return (float)(i - minBalance) * balanceStep() * 2.0 - 1.0; }
+};
+
+
+
+INTERFACE(IV4LCfg, IV4LCfgClient)
+{
+public:
+ IF_CON_DESTRUCTOR(IV4LCfg, -1)
+
+RECEIVERS:
+ IF_RECEIVER( setRadioDevice (const QString &s) )
+ IF_RECEIVER( setPlaybackMixer(const QString &soundStreamClientID, const QString &ch) )
+ IF_RECEIVER( setCaptureMixer (const QString &soundStreamClientID, const QString &ch) )
+ IF_RECEIVER( setDeviceVolume(float v) )
+ IF_RECEIVER( setActivePlayback(bool a) )
+ IF_RECEIVER( setMuteOnPowerOff(bool m) )
+ IF_RECEIVER( setVolumeZeroOnPowerOff(bool m) )
+
+SENDERS:
+ IF_SENDER ( notifyRadioDeviceChanged (const QString &s) )
+ IF_SENDER ( notifyPlaybackMixerChanged(const QString &soundStreamClientID, const QString &Channel) )
+ IF_SENDER ( notifyCaptureMixerChanged (const QString &soundStreamClientID, const QString &Channel) )
+ IF_SENDER ( notifyDeviceVolumeChanged (float v) )
+ IF_SENDER ( notifyCapabilitiesChanged (const V4LCaps &) )
+ IF_SENDER ( notifyActivePlaybackChanged (bool a) )
+ IF_SENDER ( notifyMuteOnPowerOffChanged (bool a) )
+ IF_SENDER ( notifyVolumeZeroOnPowerOffChanged (bool a) )
+
+ANSWERS:
+ IF_ANSWER ( const QString &getRadioDevice () const )
+ IF_ANSWER ( const QString &getPlaybackMixerID () const )
+ IF_ANSWER ( const QString &getCaptureMixerID () const )
+ IF_ANSWER ( const QString &getPlaybackMixerChannel() const )
+ IF_ANSWER ( const QString &getCaptureMixerChannel() const )
+ IF_ANSWER ( float getDeviceVolume() const )
+ IF_ANSWER ( V4LCaps getCapabilities(QString dev = QString::null) const )
+ IF_ANSWER ( bool getActivePlayback() const )
+ IF_ANSWER ( bool getMuteOnPowerOff() const )
+ IF_ANSWER ( bool getVolumeZeroOnPowerOff() const )
+};
+
+
+
+INTERFACE(IV4LCfgClient, IV4LCfg)
+{
+public:
+ IF_CON_DESTRUCTOR(IV4LCfgClient, 1)
+
+SENDERS:
+ IF_SENDER ( sendRadioDevice (const QString &s) )
+ IF_SENDER ( sendPlaybackMixer(const QString &soundStreamClientID, const QString &ch) )
+ IF_SENDER ( sendCaptureMixer (const QString &soundStreamClientID, const QString &ch) )
+ IF_SENDER ( sendDeviceVolume(float v) )
+ IF_SENDER ( sendActivePlayback(bool a) )
+ IF_SENDER ( sendMuteOnPowerOff(bool a) )
+ IF_SENDER ( sendVolumeZeroOnPowerOff(bool a) )
+
+RECEIVERS:
+ IF_RECEIVER( noticeRadioDeviceChanged(const QString &s) )
+ IF_RECEIVER( noticePlaybackMixerChanged(const QString &soundStreamClientID, const QString &Channel) )
+ IF_RECEIVER( noticeCaptureMixerChanged (const QString &soundStreamClientID, const QString &Channel) )
+ IF_RECEIVER( noticeDeviceVolumeChanged(float v) )
+ IF_RECEIVER( noticeCapabilitiesChanged(const V4LCaps &) )
+ IF_RECEIVER( noticeActivePlaybackChanged(bool a) )
+ IF_RECEIVER( noticeMuteOnPowerOffChanged(bool a) )
+ IF_RECEIVER( noticeVolumeZeroOnPowerOffChanged(bool a) )
+
+QUERIES:
+ IF_QUERY ( const QString &queryRadioDevice () )
+ IF_QUERY ( const QString &queryPlaybackMixerID () )
+ IF_QUERY ( const QString &queryCaptureMixerID () )
+ IF_QUERY ( const QString &queryPlaybackMixerChannel() )
+ IF_QUERY ( const QString &queryCaptureMixerChannel() )
+ IF_QUERY ( float queryDeviceVolume() )
+ IF_QUERY ( V4LCaps queryCapabilities(QString dev = QString::null) )
+ IF_QUERY ( bool queryActivePlayback() )
+ IF_QUERY ( bool queryMuteOnPowerOff() )
+ IF_QUERY ( bool queryVolumeZeroOnPowerOff() )
+
+RECEIVERS:
+ virtual void noticeConnectedI (cmplInterface *, bool /*pointer_valid*/);
+ virtual void noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/);
+};
+
+#endif
diff --git a/kradio3/plugins/v4lradio/v4lradio-configuration-ui.ui b/kradio3/plugins/v4lradio/v4lradio-configuration-ui.ui
new file mode 100644
index 0000000..2cc4cfd
--- /dev/null
+++ b/kradio3/plugins/v4lradio/v4lradio-configuration-ui.ui
@@ -0,0 +1,966 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>V4LRadioConfigurationUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>V4LRadioConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>512</width>
+ <height>357</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>SetupDialogGeneral</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>kTabWidget1</cstring>
+ </property>
+ <property name="currentPage">
+ <number>0</number>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Devices</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>spacer18_3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>labelPlaybackMixerDevice</cstring>
+ </property>
+ <property name="text">
+ <string>Playback Mixer Device</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>labelPlaybackMixerChannel</cstring>
+ </property>
+ <property name="text">
+ <string>Playback Mixer Channel</string>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer18_3_4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="3" column="2">
+ <property name="name">
+ <cstring>spacer18_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="4" column="2">
+ <property name="name">
+ <cstring>spacer18_3_4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="5" column="2">
+ <property name="name">
+ <cstring>spacer18_3_5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer18_3_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>152</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelRadioDevice</cstring>
+ </property>
+ <property name="text">
+ <string>Radio Device</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>buttonSelectRadioDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="iconSet">
+ <iconset>"fileopen"</iconset>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>labelCaptureMixerDevice</cstring>
+ </property>
+ <property name="text">
+ <string>Capture Mixer Device</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="5" column="1">
+ <property name="name">
+ <cstring>comboCaptureMixerChannel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>labelCaptureMixerChannel</cstring>
+ </property>
+ <property name="text">
+ <string>Capture Mixer Channel</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="4" column="1">
+ <property name="name">
+ <cstring>comboCaptureMixerDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>comboPlaybackMixerChannel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>test</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>comboPlaybackMixerDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>labelDescription</cstring>
+ </property>
+ <property name="text">
+ <string>unknown v4l device</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>editRadioDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="9" column="1">
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>5</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_checkboxActivePlayback</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Use active pla&amp;yback by capturing</string>
+ </property>
+ <property name="accel">
+ <string>Alt+Y</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="7" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_checkboxMuteOnPowerOff</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Mute Play&amp;back Channel on Power Off</string>
+ </property>
+ <property name="accel">
+ <string>Alt+B</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="8" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>m_checkboxVolumeZeroOnPowerOff</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Set Playback Channel Volume to &amp;Zero on Power Off</string>
+ </property>
+ <property name="accel">
+ <string>Alt+Z</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Options</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="2">
+ <property name="name">
+ <cstring>layout37</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelFrequencyRange</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>to</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>editMaxFrequency</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> kHz</string>
+ </property>
+ <property name="maxValue">
+ <number>300000</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="lineStep">
+ <number>1000</number>
+ </property>
+ <property name="value">
+ <number>300000</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>editScanStep</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> kHz</string>
+ </property>
+ <property name="maxValue">
+ <number>500</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>50</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>labelSignalMinQuality</cstring>
+ </property>
+ <property name="text">
+ <string>minimum signal quality</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>editMinFrequency</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> kHz</string>
+ </property>
+ <property name="maxValue">
+ <number>2999999</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="lineStep">
+ <number>1000</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>labelScanStep</cstring>
+ </property>
+ <property name="text">
+ <string>station scan step</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelMinMaxFrequency</cstring>
+ </property>
+ <property name="text">
+ <string>allowed frequency range</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="2" column="1">
+ <property name="name">
+ <cstring>editSignalMinQuality</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="value">
+ <number>75</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>textLabel1_4_2</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>V4L Mixer Controls</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout35</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelDeviceVolume</cstring>
+ </property>
+ <property name="text">
+ <string>volume</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout34</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer42</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>sliderDeviceVolume</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer43</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="KDoubleNumInput">
+ <property name="name">
+ <cstring>editDeviceVolume</cstring>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout35_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelTreble</cstring>
+ </property>
+ <property name="text">
+ <string>treble</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout34_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer42_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>sliderTreble</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer43_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="KDoubleNumInput">
+ <property name="name">
+ <cstring>editTreble</cstring>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="2">
+ <property name="name">
+ <cstring>layout35_2_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelBass</cstring>
+ </property>
+ <property name="text">
+ <string>bass</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout34_2_3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer42_2_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>sliderBass</cstring>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer43_2_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="KDoubleNumInput">
+ <property name="name">
+ <cstring>editBass</cstring>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="3">
+ <property name="name">
+ <cstring>layout51</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>labelBalance</cstring>
+ </property>
+ <property name="text">
+ <string>balance</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer40</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>33</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSlider">
+ <property name="name">
+ <cstring>sliderBalance</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer41</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>33</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KDoubleNumInput">
+ <property name="name">
+ <cstring>editBalance</cstring>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ <property name="maxValue">
+ <number>1</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>editRadioDevice</tabstop>
+ <tabstop>buttonSelectRadioDevice</tabstop>
+ <tabstop>comboPlaybackMixerChannel</tabstop>
+ <tabstop>editMinFrequency</tabstop>
+ <tabstop>editMaxFrequency</tabstop>
+ <tabstop>editSignalMinQuality</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+ <include location="global" impldecl="in implementation">knuminput.h</include>
+</includes>
+<pixmapfunction>SmallIconSet</pixmapfunction>
+<layoutdefaults spacing="6" margin="0"/>
+<includehints>
+ <includehint>ktabwidget.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kradio3/plugins/v4lradio/v4lradio-configuration.cpp b/kradio3/plugins/v4lradio/v4lradio-configuration.cpp
new file mode 100644
index 0000000..f7472fc
--- /dev/null
+++ b/kradio3/plugins/v4lradio/v4lradio-configuration.cpp
@@ -0,0 +1,648 @@
+/***************************************************************************
+ v4lradio-configuration.cpp - description
+ -------------------
+ begin : Fre Jun 20 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 <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/soundcard.h>
+
+#include <qspinbox.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qfile.h>
+#include <qpushbutton.h>
+#include <qslider.h>
+#include <qcheckbox.h>
+
+#include <kfiledialog.h>
+#include <knuminput.h>
+#include <klocale.h>
+#include <ktabwidget.h>
+
+#include "../../src/include/utils.h"
+#include "../../src/include/gui_list_helper.h"
+#include "v4lradio-configuration.h"
+#include "v4lradio.h"
+
+V4LRadioConfiguration::V4LRadioConfiguration (QWidget *parent, SoundStreamID ssid)
+ : V4LRadioConfigurationUI(parent),
+ m_SoundStreamID(ssid),
+ m_ignoreGUIChanges(false),
+ m_myControlChange(0),
+ m_orgTreble(-1),
+ m_orgBass(-1),
+ m_orgBalance(-2),
+ m_orgDeviceVolume(-1),
+ m_PlaybackMixerHelper(comboPlaybackMixerDevice, StringListHelper::SORT_BY_DESCR),
+ m_CaptureMixerHelper (comboCaptureMixerDevice, StringListHelper::SORT_BY_DESCR),
+ m_PlaybackChannelHelper(comboPlaybackMixerChannel),
+ m_CaptureChannelHelper (comboCaptureMixerChannel)
+{
+ QObject::connect(buttonSelectRadioDevice, SIGNAL(clicked()),
+ this, SLOT(selectRadioDevice()));
+ editRadioDevice->installEventFilter(this);
+ QObject::connect(editMinFrequency, SIGNAL(valueChanged(int)),
+ this, SLOT(guiMinFrequencyChanged(int)));
+ QObject::connect(editMaxFrequency, SIGNAL(valueChanged(int)),
+ this, SLOT(guiMaxFrequencyChanged(int)));
+
+ QObject::connect(editDeviceVolume, SIGNAL(valueChanged(double)),
+ this, SLOT(slotDeviceVolumeChanged(double)));
+ QObject::connect(editTreble, SIGNAL(valueChanged(double)),
+ this, SLOT(slotTrebleChanged(double)));
+ QObject::connect(editBass, SIGNAL(valueChanged(double)),
+ this, SLOT(slotBassChanged(double)));
+ QObject::connect(editBalance, SIGNAL(valueChanged(double)),
+ this, SLOT(slotBalanceChanged(double)));
+
+ QObject::connect(sliderDeviceVolume, SIGNAL(valueChanged(int)),
+ this, SLOT(slotDeviceVolumeChanged(int)));
+ QObject::connect(sliderTreble, SIGNAL(valueChanged(int)),
+ this, SLOT(slotTrebleChanged(int)));
+ QObject::connect(sliderBass, SIGNAL(valueChanged(int)),
+ this, SLOT(slotBassChanged(int)));
+ QObject::connect(sliderBalance, SIGNAL(valueChanged(int)),
+ this, SLOT(slotBalanceChanged(int)));
+
+ QObject::connect(comboPlaybackMixerDevice, SIGNAL(activated(int)),
+ this, SLOT(slotComboPlaybackMixerSelected(int)));
+ QObject::connect(comboCaptureMixerDevice, SIGNAL(activated(int)),
+ this, SLOT(slotComboCaptureMixerSelected(int)));
+
+ sliderBalance->installEventFilter(this);
+}
+
+
+V4LRadioConfiguration::~V4LRadioConfiguration ()
+{
+}
+
+
+bool V4LRadioConfiguration::connectI (Interface *i)
+{
+ bool a = IV4LCfgClient::connectI(i);
+ bool b = IFrequencyRadioClient::connectI(i);
+ bool c = IRadioDeviceClient::connectI(i);
+ bool d = ISoundStreamClient::connectI(i);
+ return a || b || c || d;
+}
+
+
+bool V4LRadioConfiguration::disconnectI (Interface *i)
+{
+ bool a = IV4LCfgClient::disconnectI(i);
+ bool b = IFrequencyRadioClient::disconnectI(i);
+ bool c = IRadioDeviceClient::disconnectI(i);
+ bool d = ISoundStreamClient::disconnectI(i);
+ return a || b || c || d;
+}
+
+void V4LRadioConfiguration::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_notifyTrebleChanged(this);
+ s->register4_notifyBassChanged(this);
+ s->register4_notifyBalanceChanged(this);
+ s->register4_notifySignalMinQualityChanged(this);
+
+ s->register4_notifyPlaybackChannelsChanged(this);
+ s->register4_notifyCaptureChannelsChanged(this);
+ s->register4_notifySoundStreamCreated(this);
+ }
+}
+
+void V4LRadioConfiguration::noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid)
+{
+ if (i && pointer_valid && i->supportsPlayback()) {
+ const QString &org_mid = queryPlaybackMixerID();
+ bool org_present = m_PlaybackMixerHelper.contains(org_mid);
+ const QString &mid = org_present ? m_PlaybackMixerHelper.getCurrentItem() : org_mid;
+ const QString &org_ch = queryPlaybackMixerChannel();
+ const QString &ch = org_present ? m_PlaybackChannelHelper.getCurrentText() : org_ch;
+ noticePlaybackMixerChanged(mid, ch);
+ }
+ if (i && pointer_valid && i->supportsCapture()) {
+ const QString &org_mid = queryCaptureMixerID();
+ bool org_present = m_CaptureMixerHelper.contains(org_mid);
+ const QString &mid = org_present ? m_CaptureMixerHelper.getCurrentItem() : org_mid;
+ const QString &org_ch = queryCaptureMixerChannel();
+ const QString &ch = org_present ? m_CaptureChannelHelper.getCurrentText() : org_ch;
+ noticeCaptureMixerChanged(mid, ch);
+ }
+}
+
+
+void V4LRadioConfiguration::noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid)
+{
+ if (i && pointer_valid && i->supportsPlayback()) {
+ noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel());
+ }
+ if (i && pointer_valid && i->supportsCapture()) {
+ noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel());
+ }
+}
+
+// IV4LCfgClient
+
+bool V4LRadioConfiguration::noticeRadioDeviceChanged(const QString &s)
+{
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+
+ editRadioDevice->setText(s);
+
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticePlaybackMixerChanged(const QString &_mixer_id, const QString &Channel)
+{
+ QString mixer_id = _mixer_id;
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+
+ m_PlaybackMixerHelper.setData(getPlaybackClientDescriptions());
+ m_PlaybackMixerHelper.setCurrentItem(mixer_id);
+ mixer_id = m_PlaybackMixerHelper.getCurrentItem();
+
+ ISoundStreamClient *mixer = getSoundStreamClientWithID(mixer_id);
+ if (mixer) {
+ m_PlaybackChannelHelper.setData(mixer->getPlaybackChannels());
+ m_PlaybackChannelHelper.setCurrentText(m_PlaybackChannelHelper.contains(Channel) ? Channel : queryPlaybackMixerChannel());
+ }
+ labelPlaybackMixerChannel->setEnabled(mixer != NULL);
+ comboPlaybackMixerChannel->setEnabled(mixer != NULL);
+
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeCaptureMixerChanged(const QString &_mixer_id, const QString &Channel)
+{
+ QString mixer_id = _mixer_id;
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+
+ m_CaptureMixerHelper.setData(getCaptureClientDescriptions());
+ m_CaptureMixerHelper.setCurrentItem(mixer_id);
+ mixer_id = m_CaptureMixerHelper.getCurrentItem();
+
+ ISoundStreamClient *mixer = getSoundStreamClientWithID(mixer_id);
+ if (mixer) {
+ m_CaptureChannelHelper.setData(mixer->getCaptureChannels());
+ m_CaptureChannelHelper.setCurrentText(m_CaptureChannelHelper.contains(Channel) ? Channel : queryCaptureMixerChannel());
+ }
+ labelCaptureMixerChannel->setEnabled(mixer != NULL);
+ comboCaptureMixerChannel->setEnabled(mixer != NULL);
+
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeDeviceVolumeChanged(float v)
+{
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+ v = v > 1 ? 1 : v;
+ v = v < 0 ? 0 : v;
+
+ if (!m_myControlChange)
+ m_orgDeviceVolume = v;
+
+ editDeviceVolume ->setValue(v);
+ sliderDeviceVolume->setValue(m_caps.maxVolume - m_caps.intGetVolume(v));
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeCapabilitiesChanged(const V4LCaps &c)
+{
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+
+ labelDeviceVolume ->setEnabled(c.hasVolume);
+ editDeviceVolume ->setEnabled(c.hasVolume);
+ editDeviceVolume ->setRange(0, 1, c.volumeStep(), false);
+ sliderDeviceVolume->setMinValue(0);
+ sliderDeviceVolume->setMaxValue(c.maxVolume - c.minVolume);
+ sliderDeviceVolume->setEnabled(c.hasVolume);
+
+ labelTreble ->setEnabled(c.hasTreble);
+ editTreble ->setEnabled(c.hasTreble);
+ editTreble ->setRange(0, 1, c.trebleStep(), false);
+ sliderTreble->setMinValue(0);
+ sliderTreble->setMaxValue(c.maxTreble - c.minTreble);
+ sliderTreble->setEnabled(c.hasTreble);
+
+ labelBass ->setEnabled(c.hasBass);
+ editBass ->setEnabled(c.hasBass);
+ editBass ->setRange(0, 1, c.bassStep(), false);
+ sliderBass->setMinValue(0);
+ sliderBass->setMaxValue(c.maxBass - c.minBass);
+ sliderBass->setEnabled(c.hasBass);
+
+ labelBalance ->setEnabled(c.hasBalance);
+ editBalance ->setEnabled(c.hasBalance);
+ editBalance ->setRange(-1, 1, c.balanceStep(), false);
+ sliderBalance->setMinValue(0);
+ sliderBalance->setMaxValue(c.maxBalance - c.minBalance);
+ sliderBalance->setEnabled(c.hasBalance);
+
+ m_caps = c;
+
+ float tmp = 0;
+ noticeDeviceVolumeChanged(queryDeviceVolume());
+
+ queryTreble(m_SoundStreamID, tmp);
+ noticeTrebleChanged(m_SoundStreamID, tmp);
+
+ queryBass(m_SoundStreamID, tmp);
+ noticeBassChanged(m_SoundStreamID, tmp);
+
+ queryBalance(m_SoundStreamID, tmp);
+ noticeBalanceChanged(m_SoundStreamID, tmp);
+
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+bool V4LRadioConfiguration::noticeActivePlaybackChanged(bool a)
+{
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+ m_checkboxActivePlayback->setChecked(a);
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+bool V4LRadioConfiguration::noticeMuteOnPowerOffChanged(bool a)
+{
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+ m_checkboxMuteOnPowerOff->setChecked(a);
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+bool V4LRadioConfiguration::noticeVolumeZeroOnPowerOffChanged(bool a)
+{
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+ m_checkboxVolumeZeroOnPowerOff->setChecked(a);
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+// IRadioDeviceClient
+
+bool V4LRadioConfiguration::noticeDescriptionChanged (const QString &s, const IRadioDevice */*sender*/)
+{
+ labelDescription->setText(s);
+ return true;
+}
+
+
+// IFrequencyRadioClient
+
+bool V4LRadioConfiguration::noticeFrequencyChanged(float /*f*/, const RadioStation */*s*/)
+{
+ return false; // we don't care
+}
+
+
+bool V4LRadioConfiguration::noticeMinMaxFrequencyChanged(float min, float max)
+{
+ editMinFrequency->setValue((int)rint(min*1000));
+ editMaxFrequency->setValue((int)rint(max*1000));
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeDeviceMinMaxFrequencyChanged(float min, float max)
+{
+ editMinFrequency->setMinValue((int)rint(min*1000));
+ editMaxFrequency->setMaxValue((int)rint(max*1000));
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeScanStepChanged(float s)
+{
+ editScanStep->setValue((int)rint(s * 1000));
+ return true;
+}
+
+
+// IRadioSoundClient
+
+bool V4LRadioConfiguration::noticeTrebleChanged(SoundStreamID id, float t)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+ t = t > 1 ? 1 : t;
+ t = t < 0 ? 0 : t;
+
+ if (!m_myControlChange)
+ m_orgTreble = t;
+
+ editTreble ->setValue (t);
+ sliderTreble->setValue(m_caps.maxTreble - m_caps.intGetTreble(t));
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeBassChanged(SoundStreamID id, float b)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+ b = b > 1 ? 1 : b;
+ b = b < 0 ? 0 : b;
+
+ if (!m_myControlChange)
+ m_orgBass = b;
+
+ editBass ->setValue(b);
+ sliderBass->setValue(m_caps.maxBass - m_caps.intGetBass(b));
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeBalanceChanged(SoundStreamID id, float b)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ bool old = m_ignoreGUIChanges;
+ m_ignoreGUIChanges = true;
+ b = b > 1 ? 1 : b;
+ b = b < -1 ? -1 : b;
+
+ if (!m_myControlChange)
+ m_orgBalance = b;
+
+ editBalance ->setValue(b);
+ sliderBalance->setValue(m_caps.intGetBalance(b));
+ m_ignoreGUIChanges = old;
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeSignalMinQualityChanged(SoundStreamID id, float q)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ editSignalMinQuality->setValue((int)rint(q * 100));
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeSoundStreamCreated(SoundStreamID id)
+{
+ if (id.HasSamePhysicalID(m_SoundStreamID)) {
+ m_SoundStreamID = id;
+ }
+ return true;
+}
+
+
+// GUI Slots
+
+
+void V4LRadioConfiguration::selectRadioDevice()
+{
+ KFileDialog fd("/dev/",
+ i18n("any ( * )").ascii(),
+ this,
+ i18n("Radio Device Selection").ascii(),
+ TRUE);
+ fd.setMode(KFile::File | KFile::ExistingOnly);
+ fd.setCaption (i18n("Select Radio Device"));
+
+ if (fd.exec() == QDialog::Accepted) {
+ editRadioDevice->setText(fd.selectedFile());
+ }
+}
+
+
+bool V4LRadioConfiguration::eventFilter(QObject *o, QEvent *e)
+{
+ if (e->type() == QEvent::FocusOut && o == editRadioDevice) {
+ slotEditRadioDeviceChanged();
+ }
+ if (e->type() == QEvent::MouseButtonDblClick && o == sliderBalance) {
+ slotBalanceCenter();
+ }
+ return false;
+}
+
+
+void V4LRadioConfiguration::slotEditRadioDeviceChanged()
+{
+ if (m_ignoreGUIChanges) return;
+ const QString &s = editRadioDevice->text();
+ if (s != queryRadioDevice() || !queryIsPowerOn()) {
+ V4LCaps c = queryCapabilities(s);
+ noticeDescriptionChanged(c.description);
+ } else {
+ noticeDescriptionChanged(queryDescription());
+ }
+}
+
+
+void V4LRadioConfiguration::slotComboPlaybackMixerSelected(int /*idx*/)
+{
+ if (m_ignoreGUIChanges) return;
+ QString id = m_PlaybackMixerHelper.getCurrentItem();
+ noticePlaybackMixerChanged(id, queryPlaybackMixerChannel());
+}
+
+
+void V4LRadioConfiguration::slotComboCaptureMixerSelected(int /*idx*/)
+{
+ if (m_ignoreGUIChanges) return;
+ QString id = m_CaptureMixerHelper.getCurrentItem();
+ noticeCaptureMixerChanged(id, queryCaptureMixerChannel());
+}
+
+
+void V4LRadioConfiguration::slotOK()
+{
+ sendMinFrequency(((float)editMinFrequency->value()) / 1000.0);
+ sendMaxFrequency(((float)editMaxFrequency->value()) / 1000.0);
+ sendSignalMinQuality(m_SoundStreamID, editSignalMinQuality->value() * 0.01);
+ sendRadioDevice(editRadioDevice->text());
+ sendScanStep(((float)editScanStep->value()) / 1000.0);
+
+ sendCaptureMixer (m_CaptureMixerHelper.getCurrentItem(),
+ m_CaptureChannelHelper.getCurrentText());
+ sendPlaybackMixer(m_PlaybackMixerHelper.getCurrentItem(),
+ m_PlaybackChannelHelper.getCurrentText());
+
+ sendActivePlayback(m_checkboxActivePlayback->isChecked());
+ sendMuteOnPowerOff(m_checkboxMuteOnPowerOff->isChecked());
+ sendVolumeZeroOnPowerOff(m_checkboxVolumeZeroOnPowerOff->isChecked());
+
+ queryTreble (m_SoundStreamID, m_orgTreble);
+ queryBass (m_SoundStreamID, m_orgBass);
+ queryBalance(m_SoundStreamID, m_orgBalance);
+ m_orgDeviceVolume = queryDeviceVolume();
+}
+
+
+void V4LRadioConfiguration::slotCancel()
+{
+ noticeRadioDeviceChanged(queryRadioDevice());
+ noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel());
+ noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel());
+ noticeMinMaxFrequencyChanged(queryMinFrequency(), queryMaxFrequency());
+ noticeActivePlaybackChanged(queryActivePlayback());
+ noticeMuteOnPowerOffChanged(queryMuteOnPowerOff());
+ noticeVolumeZeroOnPowerOffChanged(queryVolumeZeroOnPowerOff());
+
+ float q = 0;
+ querySignalMinQuality(m_SoundStreamID, q);
+ noticeSignalMinQualityChanged(m_SoundStreamID, q);
+ noticeScanStepChanged(queryScanStep());
+
+ sendTreble (m_SoundStreamID, m_orgTreble);
+ sendBass (m_SoundStreamID, m_orgBass);
+ sendBalance (m_SoundStreamID, m_orgBalance);
+ sendDeviceVolume(m_orgDeviceVolume);
+}
+
+
+void V4LRadioConfiguration::guiMinFrequencyChanged(int v)
+{
+ editMaxFrequency->setMinValue(v);
+}
+
+
+void V4LRadioConfiguration::guiMaxFrequencyChanged(int v)
+{
+ editMinFrequency->setMaxValue(v);
+}
+
+void V4LRadioConfiguration::slotDeviceVolumeChanged (double v) // for KDoubleNumInput, 0.0..1.0
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendDeviceVolume(v);
+ --m_myControlChange;
+}
+
+void V4LRadioConfiguration::slotTrebleChanged (double t) // for KDoubleNumInput, 0.0..1.0
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendTreble(m_SoundStreamID, t);
+ --m_myControlChange;
+}
+
+void V4LRadioConfiguration::slotBassChanged (double b) // for KDoubleNumInput, 0.0..1.0
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendBass(m_SoundStreamID, b);
+ --m_myControlChange;
+}
+
+void V4LRadioConfiguration::slotBalanceChanged(double b) // for KDoubleNumInput, -1.0..1.0
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendBalance(m_SoundStreamID, b);
+ --m_myControlChange;
+}
+
+
+void V4LRadioConfiguration::slotDeviceVolumeChanged (int v)
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendDeviceVolume(m_caps.floatGetVolume(m_caps.maxVolume - v));
+ --m_myControlChange;
+}
+
+void V4LRadioConfiguration::slotTrebleChanged (int t)
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendTreble(m_SoundStreamID, m_caps.floatGetTreble(m_caps.maxTreble - t));
+ --m_myControlChange;
+}
+
+void V4LRadioConfiguration::slotBassChanged (int b)
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendBass(m_SoundStreamID, m_caps.floatGetBass(m_caps.maxBass - b));
+ --m_myControlChange;
+}
+
+void V4LRadioConfiguration::slotBalanceChanged(int b)
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendBalance(m_SoundStreamID, m_caps.floatGetBalance(b));
+ --m_myControlChange;
+}
+
+
+void V4LRadioConfiguration::slotBalanceCenter()
+{
+ if (m_ignoreGUIChanges) return;
+ ++m_myControlChange;
+ sendBalance(m_SoundStreamID, 0);
+ --m_myControlChange;
+}
+
+
+bool V4LRadioConfiguration::noticePlaybackChannelsChanged(const QString & client_id, const QStringList &/*channels*/)
+{
+ if (m_PlaybackMixerHelper.getCurrentItem() == client_id) {
+ noticePlaybackMixerChanged(client_id, m_PlaybackChannelHelper.getCurrentText());
+ }
+ return true;
+}
+
+
+bool V4LRadioConfiguration::noticeCaptureChannelsChanged (const QString & client_id, const QStringList &/*channels*/)
+{
+ if (m_CaptureMixerHelper.getCurrentItem() == client_id) {
+ noticeCaptureMixerChanged(client_id, m_CaptureChannelHelper.getCurrentText());
+ }
+ return true;
+}
+
+
+
+#include "v4lradio-configuration.moc"
diff --git a/kradio3/plugins/v4lradio/v4lradio-configuration.h b/kradio3/plugins/v4lradio/v4lradio-configuration.h
new file mode 100644
index 0000000..bf41b54
--- /dev/null
+++ b/kradio3/plugins/v4lradio/v4lradio-configuration.h
@@ -0,0 +1,147 @@
+/***************************************************************************
+ v4lradio-configuration.h - description
+ -------------------
+ begin : Fre Jun 20 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_V4LRADIO_CONFIGURATION_H
+#define KRADIO_V4LRADIO_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/radiodevice_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "../../src/include/gui_list_helper.h"
+
+#include "v4lradio-configuration-ui.h"
+#include "v4lcfg_interfaces.h"
+
+class V4LRadio;
+class QWidget;
+
+class V4LRadioConfiguration : public V4LRadioConfigurationUI,
+ public IV4LCfgClient,
+ public IFrequencyRadioClient,
+ public ISoundStreamClient,
+ public IRadioDeviceClient
+{
+Q_OBJECT
+public :
+ V4LRadioConfiguration (QWidget *parent, SoundStreamID id);
+ ~V4LRadioConfiguration ();
+
+ bool connectI (Interface *i);
+ bool disconnectI (Interface *i);
+
+ void noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid);
+ void noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid);
+
+// IV4LCfgClient
+
+RECEIVERS:
+ bool noticeRadioDeviceChanged(const QString &s);
+ bool noticePlaybackMixerChanged(const QString &soundStreamClientID, const QString &Channel);
+ bool noticeCaptureMixerChanged (const QString &soundStreamClientID, const QString &Channel);
+ bool noticeDeviceVolumeChanged(float v);
+ bool noticeCapabilitiesChanged(const V4LCaps &c);
+ bool noticeActivePlaybackChanged(bool a);
+ bool noticeMuteOnPowerOffChanged(bool a);
+ bool noticeVolumeZeroOnPowerOffChanged(bool a);
+
+// IRadioDeviceClient
+
+RECEIVERS:
+ bool noticePowerChanged (bool /*on*/, const IRadioDevice */*sender = NULL*/) { return false; }
+ bool noticeStationChanged (const RadioStation &, const IRadioDevice */*sender = NULL*/) { return false; }
+ bool noticeDescriptionChanged (const QString &, const IRadioDevice *sender = NULL);
+
+ bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/, const IRadioDevice */*sender*/) { return false; }
+
+// IFrequencyRadioClient
+
+RECEIVERS:
+ bool noticeFrequencyChanged(float f, const RadioStation *s);
+ bool noticeMinMaxFrequencyChanged(float min, float max);
+ bool noticeDeviceMinMaxFrequencyChanged(float min, float max);
+ bool noticeScanStepChanged(float s);
+
+// ISoundStreamClient
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool noticeTrebleChanged(SoundStreamID id, float t);
+ bool noticeBassChanged(SoundStreamID id, float b);
+ bool noticeBalanceChanged(SoundStreamID id, float b);
+ bool noticeSignalMinQualityChanged(SoundStreamID id, float q);
+
+ bool noticePlaybackChannelsChanged(const QString & /*client_id*/, const QStringList &/*channels*/);
+ bool noticeCaptureChannelsChanged (const QString & /*client_id*/, const QStringList &/*channels*/);
+ bool noticeSoundStreamCreated(SoundStreamID /*id*/);
+
+
+protected:
+
+ bool eventFilter(QObject *o, QEvent *e);
+
+protected slots:
+
+ void selectRadioDevice();
+ void slotEditRadioDeviceChanged();
+ void slotComboPlaybackMixerSelected(int idx);
+ void slotComboCaptureMixerSelected(int idx);
+
+ void slotOK();
+ void slotCancel();
+
+ void guiMinFrequencyChanged(int v);
+ void guiMaxFrequencyChanged(int v);
+
+ void slotDeviceVolumeChanged (double v); // for KDoubleNumInput, 0.0..1.0
+ void slotTrebleChanged (double t); // for KDoubleNumInput, 0.0..1.0
+ void slotBassChanged (double b); // for KDoubleNumInput, 0.0..1.0
+ void slotBalanceChanged(double b); // for KDoubleNumInput, -1.0..1.0
+
+ void slotDeviceVolumeChanged (int v); // for slider, 0..65535
+ void slotTrebleChanged (int t); // for slider, 0..65535
+ void slotBassChanged (int b); // for slider, 0..65535
+ void slotBalanceChanged(int b); // for slider, 0..65535
+ void slotBalanceCenter ();
+
+protected:
+
+ SoundStreamID m_SoundStreamID;
+
+ bool m_ignoreGUIChanges;
+
+ int m_myControlChange;
+ float m_orgTreble,
+ m_orgBass,
+ m_orgBalance,
+ m_orgDeviceVolume;
+
+ V4LCaps m_caps;
+
+ typedef GUIListHelper<QComboBox, QString> StringListHelper;
+ typedef GUISimpleListHelper<QComboBox> ChannelListHelper;
+
+ StringListHelper m_PlaybackMixerHelper,
+ m_CaptureMixerHelper;
+ ChannelListHelper m_PlaybackChannelHelper,
+ m_CaptureChannelHelper;
+};
+
+#endif
diff --git a/kradio3/plugins/v4lradio/v4lradio.cpp b/kradio3/plugins/v4lradio/v4lradio.cpp
new file mode 100644
index 0000000..fb1ee9f
--- /dev/null
+++ b/kradio3/plugins/v4lradio/v4lradio.cpp
@@ -0,0 +1,1621 @@
+/***************************************************************************
+ v4lradio.cpp - description
+ -------------------
+ begin : Don Mr 8 21:57:17 CET 2001
+ copyright : (C) 2002-2005 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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#ifdef HAVE_V4L2
+#include "linux/videodev2.h"
+#endif
+#include "linux/videodev.h"
+#include <linux/soundcard.h>
+
+#include <string.h> // memcpy needed
+
+#include <qlayout.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qvaluelist.h>
+
+#include <kconfig.h>
+#include <kiconloader.h>
+#include <kdialogbase.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "../../src/include/aboutwidget.h"
+#include "../../src/include/utils.h"
+#include "v4lradio.h"
+#include "v4lradio-configuration.h"
+
+#include "../../src/include/debug-profiler.h"
+
+struct _lrvol { unsigned char l, r; short dummy; };
+
+///////////////////////////////////////////////////////////////////////
+
+PLUGIN_LIBRARY_FUNCTIONS(V4LRadio, "kradio-v4lradio", i18n("Support for V4L(2) Radio Devices"));
+
+///////////////////////////////////////////////////////////////////////
+
+V4LRadio::V4LRadio(const QString &name)
+ : PluginBase(name, i18n("Video For Linux Plugin")),
+ m_treble(0.5),
+ m_bass(0.5),
+ m_balance(0),
+ m_deviceVolume(0.9),
+ m_muted(false),
+ m_signalQuality(0),
+ m_stereo(false),
+ m_minQuality(0.75),
+ m_minFrequency(87.0),
+ m_maxFrequency(108.0),
+ m_lastMinDevFrequency(87.0),
+ m_lastMaxDevFrequency(108.0),
+
+ m_defaultPlaybackVolume(0.5),
+
+ m_scanStep(0.05),
+
+ m_radioDev("/dev/radio0"),
+ m_radio_fd(-1),
+ m_useOldV4L2Calls(true),
+ m_pollTimer(this),
+
+ m_blockReadTuner(false),
+ m_blockReadAudio(false),
+
+ m_SoundStreamID(createNewSoundStream(false)),
+ m_PlaybackMixerID(QString::null),
+ m_CaptureMixerID(QString::null),
+ m_PlaybackMixerChannel(QString::null),
+ m_CaptureMixerChannel(QString::null),
+ m_ActivePlayback(false),
+ m_MuteOnPowerOff(false),
+ m_VolumeZeroOnPowerOff(false),
+ m_restorePowerOn(false)
+{
+ QObject::connect (&m_pollTimer, SIGNAL(timeout()), this, SLOT(poll()));
+ m_pollTimer.start(333);
+
+ m_audio = new video_audio;
+ bzero(m_audio, sizeof(video_audio));
+ m_tuner = new video_tuner;
+ bzero(m_tuner, sizeof(video_tuner));
+#ifdef HAVE_V4L2
+ m_tuner2 = new v4l2_tuner;
+ bzero(m_tuner2, sizeof(v4l2_tuner));
+#endif
+ m_caps.version = 0;
+
+ m_seekHelper = new FrequencySeekHelper(*this);
+ m_seekHelper->connectI(this);
+}
+
+
+V4LRadio::~V4LRadio()
+{
+ setPower(false);
+
+ if (m_seekHelper)
+ delete m_seekHelper;
+
+ if (m_audio) delete m_audio;
+ if (m_tuner) delete m_tuner;
+#ifdef HAVE_V4L2
+ if (m_tuner2) delete m_tuner2;
+#endif
+}
+
+
+bool V4LRadio::connectI (Interface *i)
+{
+ bool a = IRadioDevice::connectI(i);
+ bool b = ISeekRadio::connectI(i);
+ bool c = IFrequencyRadio::connectI(i);
+ bool d = IV4LCfg::connectI(i);
+ bool e = PluginBase::connectI(i);
+ bool f = ISoundStreamClient::connectI(i);
+ return a || b || c || d || e || f;
+}
+
+
+bool V4LRadio::disconnectI (Interface *i)
+{
+ bool a = IRadioDevice::disconnectI(i);
+ bool b = ISeekRadio::disconnectI(i);
+ bool c = IFrequencyRadio::disconnectI(i);
+ bool d = IV4LCfg::disconnectI(i);
+ bool e = PluginBase::disconnectI(i);
+ bool f = ISoundStreamClient::disconnectI(i);
+ m_seekHelper->disconnectI(i);
+ return a || b || c || d || e || f;
+}
+
+
+void V4LRadio::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ m_seekHelper->connectI(s);
+
+ s->register4_queryPlaybackVolume(this);
+ s->register4_sendTreble(this);
+ s->register4_sendBass(this);
+ s->register4_sendBalance(this);
+ s->register4_sendMute(this);
+ s->register4_sendUnmute(this);
+ s->register4_sendSignalMinQuality(this);
+ s->register4_sendStereo(this);
+
+ s->register4_queryTreble(this);
+ s->register4_queryBass(this);
+ s->register4_queryBalance(this);
+ s->register4_querySignalQuality(this);
+ s->register4_querySignalMinQuality(this);
+ s->register4_queryHasGoodQuality(this);
+ s->register4_queryIsStereo(this);
+ s->register4_queryIsMuted(this);
+
+
+ s->register4_sendPlaybackVolume(this);
+ s->register4_sendCaptureVolume(this);
+
+ s->register4_sendStopCapture(this);
+
+ s->register4_querySoundStreamDescription(this);
+ s->register4_querySoundStreamRadioStation(this);
+ s->register4_queryEnumerateSoundStreams(this);
+
+ notifySoundStreamCreated(m_SoundStreamID);
+ }
+}
+
+void V4LRadio::noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid)
+{
+ if (i && pointer_valid && i->getSoundStreamClientID() == m_PlaybackMixerID) {
+ setPlaybackMixer(m_PlaybackMixerID, m_PlaybackMixerChannel);
+ }
+ if (i && pointer_valid && i->getSoundStreamClientID() == m_CaptureMixerID) {
+ setCaptureMixer(m_CaptureMixerID, m_CaptureMixerChannel);
+ }
+}
+
+// IRadioDevice methods
+
+bool V4LRadio::setPower (bool on)
+{
+ return on ? powerOn() : powerOff();
+}
+
+void V4LRadio::searchMixers(ISoundStreamClient **playback_mixer, ISoundStreamClient **capture_mixer)
+{
+ if (playback_mixer) {
+ *playback_mixer = getSoundStreamClientWithID(m_PlaybackMixerID);
+ if (!*playback_mixer) {
+ QPtrList<ISoundStreamClient> playback_mixers = queryPlaybackMixers();
+ if (!playback_mixers.isEmpty())
+ *playback_mixer = playback_mixers.first();
+ }
+ }
+ if (capture_mixer) {
+ *capture_mixer = getSoundStreamClientWithID(m_CaptureMixerID);
+ if (!*capture_mixer) {
+ QPtrList<ISoundStreamClient> capture_mixers = queryCaptureMixers();
+ if (!capture_mixers.isEmpty())
+ *capture_mixer = capture_mixers.first();
+ }
+ }
+}
+
+
+bool V4LRadio::powerOn ()
+{
+ if (isPowerOn())
+ return true;
+
+ radio_init();
+
+ if (isPowerOn()) {
+ ISoundStreamClient *playback_mixer = NULL,
+ *capture_mixer = NULL;
+
+ searchMixers(&playback_mixer, &capture_mixer);
+
+ if (playback_mixer)
+ playback_mixer->preparePlayback(m_SoundStreamID, m_PlaybackMixerChannel, m_ActivePlayback, false);
+ if (capture_mixer)
+ capture_mixer->prepareCapture(m_SoundStreamID, m_CaptureMixerChannel);
+
+ sendStartPlayback(m_SoundStreamID);
+ float tmp_vol = 0;
+ queryPlaybackVolume(m_SoundStreamID, tmp_vol);
+ if (tmp_vol < 0.005)
+ sendPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume);
+
+ if (m_ActivePlayback) {
+ SoundFormat sf;
+ sendStartCaptureWithFormat(m_SoundStreamID, sf, sf);
+ }
+
+ unmute(m_SoundStreamID);
+ notifyPowerChanged(true);
+ }
+
+ return true;
+}
+
+
+bool V4LRadio::powerOff ()
+{
+ if (! isPowerOn())
+ return true;
+
+ queryPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume);
+ if (m_MuteOnPowerOff)
+ sendMute(m_SoundStreamID, true);
+ if (m_VolumeZeroOnPowerOff)
+ sendPlaybackVolume(m_SoundStreamID, 0.0);
+ mute(m_SoundStreamID);
+ radio_done();
+
+ sendStopPlayback(m_SoundStreamID);
+ sendStopCapture(m_SoundStreamID);
+ closeSoundStream(m_SoundStreamID);
+ m_SoundStreamID = createNewSoundStream(m_SoundStreamID, false);
+ notifySoundStreamCreated(m_SoundStreamID);
+
+ if (isPowerOff()) {
+ notifyPowerChanged(false);
+ }
+
+ return true;
+}
+
+
+bool V4LRadio::activateStation(const RadioStation &rs)
+{
+ const FrequencyRadioStation *frs = dynamic_cast<const FrequencyRadioStation*>(&rs);
+ if (frs == NULL)
+ return false;
+
+ if (setFrequency(frs->frequency())) {
+ m_currentStation = *frs;
+
+ if (frs->initialVolume() > 0)
+ setPlaybackVolume(m_SoundStreamID, frs->initialVolume());
+
+ return true;
+ }
+
+ return false;
+}
+
+
+
+bool V4LRadio::isPowerOn() const
+{
+ return m_radio_fd >= 0;
+}
+
+
+bool V4LRadio::isPowerOff() const
+{
+ return m_radio_fd < 0;
+}
+
+
+SoundStreamID V4LRadio::getSoundStreamID() const
+{
+ return m_SoundStreamID;
+}
+
+
+const RadioStation &V4LRadio::getCurrentStation() const
+{
+ return m_currentStation;
+}
+
+
+const QString &V4LRadio::getDescription() const
+{
+ return m_caps.description;
+}
+
+
+SoundStreamID V4LRadio::getCurrentSoundStreamID() const
+{
+ return m_SoundStreamID;
+}
+
+
+
+
+bool V4LRadio::setTreble (SoundStreamID id, float t)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ if (t > 1.0) t = 1.0;
+ if (t < 0) t = 0.0;
+ if ((int)rint(m_treble*65535) != (int)rint(t*65535)) {
+ m_treble = t;
+ writeAudioInfo();
+ notifyTrebleChanged(id, t);
+ }
+ return true;
+}
+
+
+bool V4LRadio::setBass (SoundStreamID id, float b)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ if (b > 1.0) b = 1.0;
+ if (b < 0) b = 0.0;
+ if ((int)rint(m_bass*65535) != (int)rint(b*65535)) {
+ m_bass = b;
+ writeAudioInfo();
+ notifyBassChanged(id, b);
+ }
+
+ return true;
+}
+
+
+bool V4LRadio::setBalance (SoundStreamID id, float b)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ if (b > +1.0) b = +1.0;
+ if (b < -1.0) b = -1.0;
+ if ((int)rint(m_balance*32767) != (int)rint(b*32767)) {
+ m_balance = b;
+ writeAudioInfo();
+ notifyBalanceChanged(id, b);
+ }
+ return true;
+}
+
+
+bool V4LRadio::setDeviceVolume (float v)
+{
+ if (v > 1.0) v = 1.0;
+ if (v < 0) v = 0;
+ if ((int)rint(m_deviceVolume*65535) != (int)rint(v*65535)) {
+ m_deviceVolume = v;
+ writeAudioInfo();
+ notifyDeviceVolumeChanged(v);
+ }
+ return true;
+}
+
+
+bool V4LRadio::mute (SoundStreamID id, bool mute)
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ if (m_muted != mute) {
+ m_muted = mute;
+ bool r = writeAudioInfo();
+ if (r)
+ notifyMuted(id, m_muted);
+ return r;
+ }
+ return false;
+}
+
+
+bool V4LRadio::unmute (SoundStreamID id, bool unmute)
+{
+ return mute(id, !unmute);
+}
+
+
+bool V4LRadio::setSignalMinQuality (SoundStreamID id, float mq)
+{
+ if (id != m_SoundStreamID)
+ return false;
+ if (rint(mq*100) == rint(m_minQuality*100))
+ return true;
+
+ m_minQuality = mq;
+ notifySignalMinQualityChanged(id, m_minQuality);
+ return true;
+}
+
+
+bool V4LRadio::setStereo(SoundStreamID /*id*/, bool /*b*/)
+{
+ // FIXME if possible
+ return false; // we can't do that currently, not even switch stereo to mono
+}
+
+
+
+
+bool V4LRadio::getTreble (SoundStreamID id, float &t) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ readAudioInfo();
+ t = m_treble;
+ return true;
+}
+
+
+bool V4LRadio::getBass (SoundStreamID id, float &b) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ readAudioInfo();
+ b = m_bass;
+ return true;
+}
+
+
+bool V4LRadio::getBalance (SoundStreamID id, float &b) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ readAudioInfo();
+ b = m_balance;
+ return true;
+}
+
+
+float V4LRadio::getDeviceVolume () const
+{
+ readAudioInfo();
+ return m_deviceVolume;
+}
+
+
+
+bool V4LRadio::getSignalMinQuality(SoundStreamID id, float &q) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ q = m_minQuality;
+ return true;
+}
+
+
+bool V4LRadio::getSignalQuality(SoundStreamID id, float &q) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ readTunerInfo();
+ q = m_signalQuality;
+ return true;
+}
+
+
+bool V4LRadio::hasGoodQuality(SoundStreamID id, bool &good) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ float q = 0;
+ if (getSignalQuality(id, q))
+ good = q >= m_minQuality;
+ return true;
+}
+
+
+bool V4LRadio::isStereo(SoundStreamID id, bool &s) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ readAudioInfo();
+ s = m_stereo;
+ return true;
+}
+
+
+bool V4LRadio::isMuted(SoundStreamID id, bool &m) const
+{
+ if (id != m_SoundStreamID)
+ return false;
+
+ readAudioInfo();
+ m = m_muted;
+ return true;
+}
+
+
+// ISeekRadio
+
+bool V4LRadio::toBeginning()
+{
+ setFrequency(getMinFrequency());
+ return true;
+}
+
+bool V4LRadio::toEnd()
+{
+ setFrequency(getMaxFrequency());
+ return true;
+}
+
+bool V4LRadio::startSeekUp()
+{
+ return startSeek(true);
+}
+
+bool V4LRadio::startSeekDown()
+{
+ return startSeek(false);
+}
+
+bool V4LRadio::startSeek(bool up)
+{
+ if (isPowerOn() && m_seekHelper) {
+ m_seekHelper->start(m_SoundStreamID, up ? SeekHelper::up : SeekHelper::down);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool V4LRadio::stopSeek()
+{
+ if (m_seekHelper) m_seekHelper->stop();
+ return true;
+}
+
+bool V4LRadio::isSeekRunning() const
+{
+ if (m_seekHelper)
+ return m_seekHelper->isRunning();
+ else
+ return false;
+}
+
+
+bool V4LRadio::isSeekUpRunning() const
+{
+ if (m_seekHelper)
+ return m_seekHelper->isRunningUp();
+ else
+ return false;
+}
+
+
+bool V4LRadio::isSeekDownRunning() const
+{
+ if (m_seekHelper)
+ return m_seekHelper->isRunningDown();
+ else
+ return false;
+}
+
+float V4LRadio::getProgress () const
+{
+ float min = getMinFrequency();
+ float max = getMaxFrequency();
+
+ return (getFrequency() - min) / (max - min);
+}
+
+
+// IFrequencyRadio
+
+bool V4LRadio::setFrequency(float freq)
+{
+// if (isSeekRunning())
+// stopSeek();
+
+ if (m_currentStation.frequency() == freq) {
+ return true;
+ }
+
+ float minf = getMinFrequency();
+ float maxf = getMaxFrequency();
+
+ if (isPowerOn()) {
+
+ bool oldMute = false;
+ isMuted(m_SoundStreamID, oldMute);
+ if (!oldMute && !m_ActivePlayback)
+ mute(m_SoundStreamID);
+
+
+ if (!m_tunercache.valid) readTunerInfo();
+ float df = m_tunercache.deltaF;
+
+ unsigned long lfreq = (unsigned long) rint(freq / df);
+
+ if (freq > maxf || freq < minf) {
+ logError("V4LRadio::setFrequency: " +
+ i18n("invalid frequency %1").arg(QString().setNum(freq)));
+ if (!oldMute && !m_ActivePlayback)
+ unmute(m_SoundStreamID);
+ return false;
+ }
+
+ int r = -1;
+ if (m_caps.version == 1) {
+ r = ioctl(m_radio_fd, VIDIOCSFREQ, &lfreq);
+ }
+#ifdef HAVE_V4L2
+ else if (m_caps.version == 2) {
+ v4l2_frequency tmp;
+ tmp.tuner = 0;
+ tmp.type = V4L2_TUNER_RADIO;
+ tmp.frequency = lfreq;
+ r = ioctl(m_radio_fd, VIDIOC_S_FREQUENCY, &tmp);
+ }
+#endif
+ else {
+ logError("V4LRadio::setFrequency: " +
+ i18n("don't known how to handle V4L-version %1")
+ .arg(m_caps.version));
+ }
+
+ if (r) {
+ logError("V4LRadio::setFrequency: " +
+ i18n("error setting frequency to %1 (%2)")
+ .arg(QString().setNum(freq))
+ .arg(QString().setNum(r)));
+ // unmute the old radio with the old radio station
+ if (!oldMute && !m_ActivePlayback)
+ unmute(m_SoundStreamID);
+ return false;
+ }
+
+ // unmute this radio device, because we now have the current
+ // radio station
+ if (!oldMute && !m_ActivePlayback)
+ unmute(m_SoundStreamID);
+ }
+
+ m_currentStation.setFrequency(freq);
+ notifyFrequencyChanged(freq, &m_currentStation);
+ notifyStationChanged(m_currentStation);
+ notifyProgress((freq - minf) / (maxf - minf));
+ notifySoundStreamChanged(m_SoundStreamID);
+ return true;
+}
+
+
+bool V4LRadio::setMinFrequency (float minF)
+{
+ float oldm = getMinFrequency();
+ m_minFrequency = minF;
+
+ float newm = getMinFrequency();
+ if (oldm != newm)
+ notifyMinMaxFrequencyChanged(newm, getMaxFrequency());
+
+ return true;
+}
+
+
+bool V4LRadio::setMaxFrequency (float maxF)
+{
+ float oldm = getMaxFrequency();
+ m_maxFrequency = maxF;
+
+ float newm = getMaxFrequency();
+ if (oldm != newm)
+ notifyMinMaxFrequencyChanged(getMinFrequency(), newm);
+
+ return true;
+}
+
+
+bool V4LRadio::setScanStep(float s)
+{
+ float old = m_scanStep;
+ m_scanStep = s;
+
+ if (old != s) notifyScanStepChanged(m_scanStep);
+ return true;
+}
+
+
+float V4LRadio::getFrequency() const
+{
+ return m_currentStation.frequency();
+}
+
+
+float V4LRadio::getMinFrequency() const
+{
+ return m_minFrequency ? m_minFrequency : getMinDeviceFrequency();
+}
+
+
+float V4LRadio::getMaxFrequency() const
+{
+ return m_maxFrequency ? m_maxFrequency : getMaxDeviceFrequency();
+}
+
+
+float V4LRadio::getMinDeviceFrequency() const
+{
+ if (!m_tunercache.valid)
+ readTunerInfo();
+
+ return m_tunercache.minF;
+}
+
+
+float V4LRadio::getMaxDeviceFrequency() const
+{
+ if (!m_tunercache.valid)
+ readTunerInfo();
+
+ return m_tunercache.maxF;
+}
+
+
+float V4LRadio::getScanStep() const
+{
+ return m_scanStep;
+}
+
+
+
+// IV4LCfg methods
+
+bool V4LRadio::setRadioDevice(const QString &s)
+{
+ if (m_radioDev != s) {
+ bool p = isPowerOn();
+ powerOff();
+ m_radioDev = s;
+
+ m_caps = readV4LCaps(m_radioDev);
+ notifyRadioDeviceChanged(m_radioDev);
+ notifyDescriptionChanged(m_caps.description);
+ notifyCapabilitiesChanged(m_caps);
+ setPower(p);
+ }
+ return true;
+}
+
+
+bool V4LRadio::setPlaybackMixer(const QString &soundStreamClientID, const QString &ch)
+{
+ bool change = m_PlaybackMixerID != soundStreamClientID || m_PlaybackMixerChannel != ch;
+ m_PlaybackMixerID = soundStreamClientID;
+ m_PlaybackMixerChannel = ch;
+
+
+ if (isPowerOn()) {
+ queryPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume);
+ sendStopPlayback(m_SoundStreamID);
+ sendReleasePlayback(m_SoundStreamID);
+ }
+
+ ISoundStreamClient *playback_mixer = NULL;
+ searchMixers(&playback_mixer, NULL);
+ if (playback_mixer)
+ playback_mixer->preparePlayback(m_SoundStreamID, m_PlaybackMixerChannel, m_ActivePlayback, false);
+
+ if (isPowerOn()) {
+ sendStartPlayback(m_SoundStreamID);
+ sendPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume);
+ if (m_ActivePlayback) {
+ SoundFormat sf;
+ sendStartCaptureWithFormat(m_SoundStreamID, sf, sf);
+ }
+ }
+
+ if (change)
+ notifyPlaybackMixerChanged(soundStreamClientID, ch);
+
+ return true;
+}
+
+
+bool V4LRadio::setCaptureMixer(const QString &soundStreamClientID, const QString &ch)
+{
+ bool change = m_PlaybackMixerID != soundStreamClientID || m_PlaybackMixerChannel != ch;
+ m_CaptureMixerID = soundStreamClientID;
+ m_CaptureMixerChannel = ch;
+
+ bool r = false;
+ SoundFormat sf;
+ queryIsCaptureRunning(m_SoundStreamID, r, sf);
+
+ float v = 0;
+ if (isPowerOn() && r) {
+ queryCaptureVolume(m_SoundStreamID, v);
+ sendStopCapture(m_SoundStreamID);
+ sendReleaseCapture(m_SoundStreamID);
+ }
+
+ ISoundStreamClient *capture_mixer = NULL;
+ searchMixers(NULL, &capture_mixer);
+ if (capture_mixer)
+ capture_mixer->prepareCapture(m_SoundStreamID, m_CaptureMixerChannel);
+
+ if (isPowerOn() && r) {
+ sendStartCaptureWithFormat(m_SoundStreamID, sf, sf);
+ sendCaptureVolume(m_SoundStreamID, v);
+ }
+
+ if (change)
+ notifyCaptureMixerChanged(soundStreamClientID, ch);
+
+ return true;
+}
+
+
+V4LCaps V4LRadio::getCapabilities(QString dev) const
+{
+ if (dev.isNull()) {
+ return m_caps;
+ } else {
+ return readV4LCaps(dev);
+ }
+}
+
+
+bool V4LRadio::setActivePlayback(bool a)
+{
+ if (a == m_ActivePlayback)
+ return true;
+
+
+ if (isPowerOn()) {
+ queryPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume);
+ sendStopPlayback(m_SoundStreamID);
+ sendReleasePlayback(m_SoundStreamID);
+ if (m_ActivePlayback) {
+ sendStopCapture(m_SoundStreamID);
+ }
+ }
+
+ m_ActivePlayback = a;
+
+ ISoundStreamClient *playback_mixer = NULL;
+ searchMixers(&playback_mixer, NULL);
+ if (playback_mixer)
+ playback_mixer->preparePlayback(m_SoundStreamID, m_PlaybackMixerChannel, m_ActivePlayback, false);
+
+ if (isPowerOn()) {
+ sendStartPlayback(m_SoundStreamID);
+ sendPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume);
+ if (m_ActivePlayback) {
+ SoundFormat sf;
+ sendStartCaptureWithFormat(m_SoundStreamID, sf, sf);
+ }
+ }
+
+ // FIXME: restart playback/capture
+ notifyActivePlaybackChanged(m_ActivePlayback);
+
+ return true;
+}
+
+bool V4LRadio::setMuteOnPowerOff(bool a)
+{
+ if (a != m_MuteOnPowerOff) {
+ m_MuteOnPowerOff = a;
+ notifyMuteOnPowerOffChanged(m_MuteOnPowerOff);
+ }
+ return true;
+}
+
+bool V4LRadio::setVolumeZeroOnPowerOff(bool a)
+{
+ if (a != m_VolumeZeroOnPowerOff) {
+ m_VolumeZeroOnPowerOff = a;
+ notifyVolumeZeroOnPowerOffChanged(m_VolumeZeroOnPowerOff);
+ }
+ return true;
+}
+
+// PluginBase methods
+
+void V4LRadio::saveState (KConfig *config) const
+{
+ config->setGroup(QString("v4lradio-") + name());
+
+ config->writeEntry("RadioDev", m_radioDev);
+
+ config->writeEntry("PlaybackMixerID", m_PlaybackMixerID);
+ config->writeEntry("PlaybackMixerChannel", m_PlaybackMixerChannel);
+ config->writeEntry("CaptureMixerID", m_CaptureMixerID);
+ config->writeEntry("CaptureMixerChannel", m_CaptureMixerChannel);
+
+ config->writeEntry("fMinOverride", m_minFrequency);
+ config->writeEntry("fMaxOverride", m_maxFrequency);
+ config->writeEntry("fLastDevMin", m_lastMinDevFrequency);
+ config->writeEntry("fLastDevMax", m_lastMaxDevFrequency);
+
+ config->writeEntry("defaultPlaybackVolume", m_defaultPlaybackVolume);
+
+ config->writeEntry("signalMinQuality", m_minQuality);
+
+ config->writeEntry("scanStep", m_scanStep);
+
+ config->writeEntry("Frequency", m_currentStation.frequency());
+ config->writeEntry("Treble", m_treble);
+ config->writeEntry("Bass", m_bass);
+ config->writeEntry("Balance", m_balance);
+ config->writeEntry("DeviceVolume", m_deviceVolume);
+
+ config->writeEntry("PowerOn", isPowerOn());
+ config->writeEntry("UseOldV4L2Calls", m_useOldV4L2Calls);
+
+ config->writeEntry("ActivePlayback", m_ActivePlayback);
+ config->writeEntry("MuteOnPowerOff", m_MuteOnPowerOff);
+ config->writeEntry("VolumeZeroOnPowerOff", m_VolumeZeroOnPowerOff);
+}
+
+
+void V4LRadio::restoreState (KConfig *config)
+{
+ BlockProfiler p("V4LRadio::restoreState");
+
+ config->setGroup(QString("v4lradio-") + name());
+
+ QString base_devname = "/dev/radio";
+
+ QStringList testlist (base_devname );
+ for (int i = 0; i < 9; ++i)
+ testlist.append(base_devname + QString::number(i));
+
+ QString found_devname(QString::null);
+ for (QValueListConstIterator<QString> it = testlist.begin(); it != testlist.end(); ++it) {
+ QFile f(*it);
+ if (f.exists()) {
+ QFileInfo info(f);
+ if (info.isReadable() && info.isWritable()) {
+ found_devname = *it;
+ break;
+ }
+ else {
+ if (found_devname.isNull())
+ found_devname = *it;
+ logWarning(i18n("Device %1 does exist but is not readable/writable. Please check device permissions.").arg(*it));
+ }
+ }
+ }
+
+ QString default_devname = found_devname.isNull() ? base_devname : found_devname;
+
+ QString devname = config->readEntry ("RadioDev", default_devname);
+
+ if (found_devname.isNull() && devname == default_devname) {
+ logError(i18n("Could not find an accessible v4l(2) radio device."));
+ }
+
+ setRadioDevice(devname);
+
+ QString PlaybackMixerID = config->readEntry ("PlaybackMixerID", QString::null);
+ QString PlaybackMixerChannel = config->readEntry ("PlaybackMixerChannel", "Line");
+
+ QString CaptureMixerID = config->readEntry ("CaptureMixerID", QString::null);
+ QString CaptureMixerChannel = config->readEntry ("CaptureMixerChannel", "Line");
+
+ m_ActivePlayback = config->readBoolEntry("ActivePlayback", false);
+ m_MuteOnPowerOff = config->readBoolEntry("MuteOnPowerOff", false);
+ m_VolumeZeroOnPowerOff = config->readBoolEntry("VolumeZeroOnPowerOff", false);
+
+ m_lastMinDevFrequency = config->readDoubleNumEntry ("fLastDevMin", 65.0);
+ m_lastMaxDevFrequency = config->readDoubleNumEntry ("fLastDevMax", 108.0);
+ m_minFrequency = config->readDoubleNumEntry ("fMinOverride", m_lastMinDevFrequency);
+ m_maxFrequency = config->readDoubleNumEntry ("fMaxOverride", m_lastMaxDevFrequency);
+
+ m_minQuality = config->readDoubleNumEntry ("signalMinQuality", 0.75);
+ m_scanStep = config->readDoubleNumEntry ("scanStep", 0.05);
+ m_defaultPlaybackVolume = config->readDoubleNumEntry ("defaultPlaybackVolume", 0.5);
+
+ setPlaybackMixer(PlaybackMixerID, PlaybackMixerChannel);
+ setCaptureMixer (CaptureMixerID, CaptureMixerChannel);
+ notifyDeviceMinMaxFrequencyChanged(m_lastMinDevFrequency, m_lastMaxDevFrequency);
+ notifyMinMaxFrequencyChanged(m_minFrequency, m_maxFrequency);
+ notifySignalMinQualityChanged(m_SoundStreamID, m_minQuality);
+ notifyScanStepChanged(m_scanStep);
+ notifyActivePlaybackChanged(m_ActivePlayback);
+ notifyMuteOnPowerOffChanged(m_MuteOnPowerOff);
+ notifyVolumeZeroOnPowerOffChanged(m_VolumeZeroOnPowerOff);
+
+ BlockProfiler p2("V4LRadio::restoreState2");
+
+ setFrequency(config->readDoubleNumEntry("Frequency", 88));
+ m_restorePowerOn = config->readBoolEntry ("PowerOn", false);
+
+ BlockProfiler p3("V4LRadio::restoreState3");
+
+ setTreble (m_SoundStreamID, config->readDoubleNumEntry("Treble", 0.5));
+ setBass (m_SoundStreamID, config->readDoubleNumEntry("Bass", 0.5));
+ setBalance (m_SoundStreamID, config->readDoubleNumEntry("Balance", 0.0));
+ setDeviceVolume( config->readDoubleNumEntry("DeviceVolume", 0.9));
+
+ m_useOldV4L2Calls = config->readBoolEntry("UseOldV4L2Calls", true);
+
+ if (isPowerOff())
+ notifyPlaybackVolumeChanged(m_SoundStreamID, m_defaultPlaybackVolume);
+}
+
+void V4LRadio::startPlugin()
+{
+ PluginBase::startPlugin();
+ setPower(m_restorePowerOn);
+}
+
+ConfigPageInfo V4LRadio::createConfigurationPage()
+{
+ V4LRadioConfiguration *v4lconf = new V4LRadioConfiguration(NULL, m_SoundStreamID);
+ connectI(v4lconf);
+ return ConfigPageInfo (v4lconf,
+ i18n("V4L Radio"),
+ i18n("V4L Radio Options"),
+ "package_utilities");
+}
+
+
+AboutPageInfo V4LRadio::createAboutPage()
+{
+ KAboutData aboutData("kradio",
+ NULL,
+ NULL,
+ I18N_NOOP("V4L/V4L2 Plugin for KRadio."
+ "<P>"
+ "Provides Support for V4L/V4L2 based Radio Cards"
+ "<P>"),
+ 0,
+ //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("V4L/V4L2"),
+ i18n("V4L/V4L2 Plugin"),
+ "package_utilities"
+ );
+}
+
+////////////////////////////////////////
+// anything else
+
+void V4LRadio::radio_init()
+{
+ if (isSeekRunning())
+ stopSeek();
+
+ m_caps = readV4LCaps(m_radioDev);
+ notifyCapabilitiesChanged(m_caps);
+ notifyDescriptionChanged(m_caps.description);
+
+/* m_mixer_fd = open(m_mixerDev, O_RDONLY);
+ if (m_mixer_fd < 0) {
+ radio_done();
+
+ logError("V4LRadio::radio_init: " +
+ i18n("Cannot open mixer device %1").arg(m_mixerDev));
+ return;
+ }
+*/
+ m_radio_fd = open(m_radioDev.ascii(), O_RDONLY);
+ if (m_radio_fd < 0) {
+ radio_done();
+
+ logError("V4LRadio::radio_init: " +
+ i18n("Cannot open radio device %1").arg(m_radioDev));
+ return;
+ }
+
+ readTunerInfo();
+ writeAudioInfo(); // set tuner-audio config as used last time
+ readAudioInfo(); // reread tuner-audio and read-only flags (e.g. stereo)
+
+ // restore frequency
+ float old = getFrequency();
+ m_currentStation.setFrequency(0);
+ setFrequency(old);
+
+ // read volume level from mixer
+ // FIXME: do we still need this
+/* float v = 0;
+ getVolume(m_SoundStreamID, v)
+ setVolume (m_SoundStreamID, v);*/
+}
+
+
+void V4LRadio::radio_done()
+{
+ if (isSeekRunning())
+ stopSeek();
+
+ if (m_radio_fd >= 0) close (m_radio_fd);
+// if (m_mixer_fd >= 0) close (m_mixer_fd);
+
+ m_radio_fd = -1;
+// m_mixer_fd = -1;
+}
+
+
+
+
+
+#define CAPS_NAME_LEN 127
+V4LCaps V4LRadio::readV4LCaps(const QString &device) const
+{
+ char buffer[CAPS_NAME_LEN+1];
+ int r;
+ int fd;
+
+ V4LCaps c;
+ c.description = device;
+
+ fd = open(device.ascii(), O_RDONLY);
+
+ if (fd < 0) {
+ logError("V4LRadio::readV4LCaps: " +
+ i18n("cannot open %1").arg(device));
+ return c;
+ }
+
+ video_capability caps;
+ r = ioctl(fd, VIDIOCGCAP, &caps);
+ if (r == 0) {
+ c.version = 1;
+
+ size_t l = sizeof(caps.name);
+ l = l < CAPS_NAME_LEN ? l : CAPS_NAME_LEN;
+ memcpy(buffer, caps.name, l);
+ buffer[l] = 0;
+ c.description = buffer;
+
+ c.hasMute = false;
+ c.unsetVolume();
+ c.unsetTreble();
+ c.unsetBass();
+ c.unsetBalance();
+
+ video_audio audiocaps;
+ if (0 == ioctl(fd, VIDIOCGAUDIO, &audiocaps)) {
+ logDebug("V4LRadio::readV4LCaps: " +
+ i18n("audio caps = %1").arg(QString().setNum(audiocaps.flags)));
+ if ((audiocaps.flags & VIDEO_AUDIO_MUTABLE) != 0)
+ c.hasMute = true;
+ if ((audiocaps.flags & VIDEO_AUDIO_VOLUME) != 0)
+ c.setVolume (0, 65535);
+ if ((audiocaps.flags & VIDEO_AUDIO_TREBLE) != 0)
+ c.setTreble (0, 65535);
+ if ((audiocaps.flags & VIDEO_AUDIO_BASS) != 0)
+ c.setBass (0, 65535);
+ // at least my driver has support for balance, but the bit is not set ...
+ c.setBalance(0, 65535);
+ }
+ } else {
+ logError("V4LRadio::readV4LCaps: " +
+ i18n("error reading V4L1 caps"));
+ }
+
+#ifdef HAVE_V4L2
+ v4l2_capability caps2;
+ r = ioctl(fd, VIDIOC_QUERYCAP, &caps2);
+ if (r == 0) {
+ c.version = 2;
+
+ logDebug(i18n("V4L2 - Version: %1").arg(QString().sprintf("%08X", caps2.version)));
+
+ size_t l = sizeof(caps.name);
+ l = l < CAPS_NAME_LEN ? l : CAPS_NAME_LEN;
+ memcpy(buffer, caps.name, l);
+ buffer[l] = 0;
+ // c.description = buffer;
+
+ v4l2_queryctrl ctrl;
+
+ c.hasMute = false;
+ c.unsetVolume();
+ c.unsetTreble();
+ c.unsetBass();
+ c.unsetBalance();
+
+ ctrl.id = V4L2_CID_AUDIO_MUTE;
+ if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl))
+ c.hasMute = !(ctrl.flags & V4L2_CTRL_FLAG_DISABLED);
+ else
+ logError(i18n("V4L2: Querying mute control failed"));
+
+ ctrl.id = V4L2_CID_AUDIO_VOLUME;
+ if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED))
+ c.setVolume(ctrl.minimum, ctrl.maximum);
+ } else {
+ logError(i18n("V4L2: Querying volume control failed"));
+ }
+
+ ctrl.id = V4L2_CID_AUDIO_TREBLE;
+ if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED))
+ c.setTreble(ctrl.minimum, ctrl.maximum);
+ } else {
+ logError(i18n("V4L2: Querying treble control failed"));
+ }
+
+ ctrl.id = V4L2_CID_AUDIO_BASS;
+ if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED))
+ c.setBass(ctrl.minimum, c.maxBass = ctrl.maximum);
+ } else {
+ logError(i18n("V4L2: Querying bass control failed"));
+ }
+
+ ctrl.id = V4L2_CID_AUDIO_BALANCE;
+ if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) {
+ if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED))
+ c.setBalance(ctrl.minimum, ctrl.maximum);
+ } else {
+ logError(i18n("V4L2: Querying balance control failed"));
+ }
+
+ } else {
+ logWarning(i18n("V4LRadio::readV4LCaps: Reading V4L2 caps failed"));
+ }
+#endif
+ if (c.version > 0) {
+ logInfo(i18n("V4L %1 detected").arg(c.version));
+ } else {
+ logError(i18n("V4L not detected"));
+ }
+
+ logInfo(c.hasMute ? i18n("Radio is mutable") : i18n("Radio is not mutable"));
+ logInfo(c.hasVolume ? i18n("Radio has Volume Control") : i18n("Radio has no Volume Control"));
+ logInfo(c.hasBass ? i18n("Radio has Bass Control") : i18n("Radio has no Bass Control"));
+ logInfo(c.hasTreble ? i18n("Radio has Treble Control") : i18n("Radio has no Treble Control"));
+
+ close(fd);
+ return c;
+}
+
+
+bool V4LRadio::readTunerInfo() const
+{
+ if (m_blockReadTuner) return true;
+
+ float oldq = m_signalQuality;
+ float oldminf = m_tunercache.minF;
+ float oldmaxf = m_tunercache.maxF;
+
+ if (!m_tunercache.valid) {
+ m_tunercache.minF = m_lastMinDevFrequency;
+ m_tunercache.maxF = m_lastMaxDevFrequency;
+ m_tunercache.deltaF = 1.0/16.0;
+ m_tunercache.valid = true;
+ }
+
+ int r = 0;
+ if (isPowerOn()) {
+
+ // v4l1
+ if (m_caps.version == 1) {
+
+ r = ioctl(m_radio_fd, VIDIOCGTUNER, m_tuner);
+
+ if (r == 0) {
+ if ((m_tuner->flags & VIDEO_TUNER_LOW) != 0)
+ m_tunercache.deltaF = 1.0 / 16000.0;
+ m_tunercache.minF = float(m_tuner->rangelow) * m_tunercache.deltaF;
+ m_tunercache.maxF = float(m_tuner->rangehigh) * m_tunercache.deltaF;
+ m_tunercache.valid = true;
+ m_signalQuality = float(m_tuner->signal) / 32767.0;
+
+ }
+ }
+#ifdef HAVE_V4L2
+ // v4l2
+ else if (m_caps.version == 2) {
+
+ r = ioctl(m_radio_fd, VIDIOC_G_TUNER, m_tuner2);
+
+ if (r == 0) {
+ if ((m_tuner2->capability & V4L2_TUNER_CAP_LOW) != 0)
+ m_tunercache.deltaF = 1.0 / 16000.0;
+ m_tunercache.minF = float(m_tuner2->rangelow) * m_tunercache.deltaF;
+ m_tunercache.maxF = float(m_tuner2->rangehigh) * m_tunercache.deltaF;
+ m_tunercache.valid = true;
+ m_signalQuality = float(m_tuner2->signal) / 32767.0;
+ }
+ }
+#endif
+ else {
+ logError("V4LRadio::readTunerInfo: " +
+ i18n("don't known how to handle V4L-version %1")
+ .arg(QString().setNum(m_caps.version)));
+ }
+
+ if (r != 0) {
+ m_signalQuality = 0;
+ logError("V4LRadio::readTunerInfo: " +
+ i18n("cannot get tuner info (error %1)").arg(QString().setNum(r)));
+ }
+ } else {
+ m_signalQuality = 0;
+ }
+
+ // prevent loops, if noticeXYZ-method is reading my state
+ m_blockReadTuner = true;
+
+ if (oldminf != m_tunercache.minF || oldmaxf != m_tunercache.maxF)
+ notifyDeviceMinMaxFrequencyChanged(m_tunercache.minF, m_tunercache.maxF);
+ m_lastMinDevFrequency = m_tunercache.minF;
+ m_lastMaxDevFrequency = m_tunercache.maxF;
+
+ if ( ! m_minFrequency && (oldminf != m_tunercache.minF)
+ || ! m_maxFrequency && (oldmaxf != m_tunercache.maxF))
+ notifyMinMaxFrequencyChanged(getMinFrequency(), getMaxFrequency());
+
+
+ if (m_signalQuality != oldq)
+ notifySignalQualityChanged(m_SoundStreamID, m_signalQuality);
+ if ( (m_signalQuality >= m_minQuality) != (oldq >= m_minQuality))
+ notifySignalQualityBoolChanged(m_SoundStreamID, m_signalQuality > m_minQuality);
+
+ m_blockReadTuner = false;
+
+ return true;
+}
+
+
+
+#define V4L2_S_CTRL(what,val) \
+ { ctl.value = (val); \
+ ctl.id = (what); \
+ /* Problem: Current V4L2 development has changed the IOCTL-IDs for VIDIOC_S_CTRL */ \
+ /* => we must du "try and error" to figure out what version we should use */ \
+ r = ioctl (m_radio_fd, m_useOldV4L2Calls ? VIDIOC_S_CTRL_OLD : VIDIOC_S_CTRL, &ctl); \
+ /* in case this did not work, try the other version of the call */ \
+ if (r) { \
+ r = ioctl (m_radio_fd, !m_useOldV4L2Calls ? VIDIOC_S_CTRL_OLD : VIDIOC_S_CTRL, &ctl); \
+ if (!r) m_useOldV4L2Calls = !m_useOldV4L2Calls; \
+ } \
+ x = x ? x : r; \
+ if (r) \
+ logError(i18n("error setting %1: %2").arg(#what).arg(QString().setNum(r))); \
+ }
+
+#define V4L2_G_CTRL(what) \
+ { ctl.id = (what); \
+ r = ioctl (m_radio_fd, VIDIOC_G_CTRL, &ctl); \
+ x = x ? x : r; \
+ if (r) \
+ logError(i18n("error reading %1: %2").arg(#what).arg(QString().setNum(r))); \
+ }
+
+
+bool V4LRadio::updateAudioInfo(bool write) const
+{
+ if (m_blockReadAudio && !write)
+ return true;
+
+ bool oldStereo = m_stereo;
+ bool oldMute = m_muted;
+ int iOldDeviceVolume = m_caps.intGetVolume (m_deviceVolume);
+ int iOldTreble = m_caps.intGetTreble (m_treble);
+ int iOldBass = m_caps.intGetBass (m_bass);
+ int iOldBalance = m_caps.intGetBalance(m_balance);
+
+ if (isPowerOn()) {
+ int r = 0;
+ if (m_caps.version == 1) {
+ m_audio->audio = 0;
+ if (m_muted) m_audio->flags |= VIDEO_AUDIO_MUTE;
+ else m_audio->flags &= ~VIDEO_AUDIO_MUTE;
+
+ m_audio->volume = m_caps.intGetVolume (m_deviceVolume);
+ m_audio->treble = m_caps.intGetTreble (m_treble);
+ m_audio->bass = m_caps.intGetBass (m_bass);
+ m_audio->balance = m_caps.intGetBalance(m_balance);
+
+ r = ioctl(m_radio_fd, write ? VIDIOCSAUDIO : VIDIOCGAUDIO, m_audio);
+
+ m_stereo = (r == 0) && ((m_audio->mode & VIDEO_SOUND_STEREO) != 0);
+
+ m_muted = m_caps.hasMute &&
+ ((r != 0) || ((m_audio->flags & VIDEO_AUDIO_MUTE) != 0));
+
+ /* Some drivers seem to set volumes to zero if they are muted.
+ Thus we do not reload them if radio is muted */
+ if (!m_muted && !write) {
+ m_deviceVolume = m_caps.hasVolume && !r ? m_caps.floatGetVolume (m_audio->volume) : 1;
+ m_treble = m_caps.hasTreble && !r ? m_caps.floatGetTreble (m_audio->treble) : 1;
+ m_bass = m_caps.hasBass && !r ? m_caps.floatGetBass (m_audio->bass) : 1;
+ m_balance = m_caps.hasBalance && !r ? m_caps.floatGetBalance(m_audio->balance) : 0;
+ }
+ }
+#ifdef HAVE_V4L2
+ else if (m_caps.version == 2) {
+ v4l2_control ctl;
+ int x = 0; // x stores first ioctl error
+ if (write) {
+ if (m_caps.hasMute)
+ V4L2_S_CTRL(V4L2_CID_AUDIO_MUTE, m_muted);
+ if (m_caps.hasTreble)
+ V4L2_S_CTRL(V4L2_CID_AUDIO_TREBLE, m_caps.intGetTreble(m_treble));
+ if (m_caps.hasBass)
+ V4L2_S_CTRL(V4L2_CID_AUDIO_BASS, m_caps.intGetBass(m_bass));
+ if (m_caps.hasBalance)
+ V4L2_S_CTRL(V4L2_CID_AUDIO_BALANCE, m_caps.intGetBalance(m_balance));
+ if (m_caps.hasVolume)
+ V4L2_S_CTRL(V4L2_CID_AUDIO_VOLUME, m_caps.intGetVolume(m_deviceVolume));
+ } else {
+ if (m_caps.hasMute)
+ V4L2_G_CTRL(V4L2_CID_AUDIO_MUTE);
+ m_muted = m_caps.hasMute && ((r != 0) || ctl.value);
+
+ /* Some drivers seem to set volumes to zero if they are muted.
+ Thus we do not reload them if radio is muted */
+ if (!m_muted) {
+ if (m_caps.hasVolume)
+ V4L2_G_CTRL(V4L2_CID_AUDIO_VOLUME);
+ m_deviceVolume = m_caps.hasVolume && !r ? m_caps.floatGetVolume (ctl.value) : 1;
+ if (m_caps.hasTreble)
+ V4L2_G_CTRL(V4L2_CID_AUDIO_TREBLE);
+ m_treble = m_caps.hasTreble && !r ? m_caps.floatGetTreble (ctl.value) : 1;
+ if (m_caps.hasBass)
+ V4L2_G_CTRL(V4L2_CID_AUDIO_BASS);
+ m_bass = m_caps.hasBass && !r ? m_caps.floatGetBass (ctl.value) : 1;
+ if (m_caps.hasBalance)
+ V4L2_G_CTRL(V4L2_CID_AUDIO_BALANCE);
+ m_balance = m_caps.hasBalance&& !r ? m_caps.floatGetBalance(ctl.value) : 0;
+ }
+
+ r = ioctl (m_radio_fd, VIDIOC_G_TUNER, m_tuner2);
+ m_stereo = (r == 0) && ((m_tuner2->rxsubchans & V4L2_TUNER_SUB_STEREO) != 0);
+ x = x ? x : r;
+ }
+ r = x; // store first error back to r, used below for error message
+ }
+#endif
+ else {
+ logError("V4LRadio::updateAudioInfo: " +
+ i18n("don't known how to handle V4L-version %1")
+ .arg(QString().setNum(m_caps.version)));
+ }
+
+ if (r) {
+ logError("V4LRadio::updateAudioInfo: " +
+ i18n("error updating radio audio info (%1): %2")
+ .arg(write ? i18n("write") : i18n("read"))
+ .arg(QString().setNum(r)));
+ return false;
+ }
+ }
+
+ // prevent loops, if noticeXYZ-method is reading my state
+ bool oldBlock = m_blockReadAudio;
+ m_blockReadAudio = true;
+
+ // send notifications
+
+ if (oldStereo != m_stereo)
+ notifyStereoChanged(m_SoundStreamID, m_stereo);
+ if (oldMute != m_muted)
+ notifyMuted(m_SoundStreamID, m_muted);
+ if (iOldDeviceVolume != m_caps.intGetVolume(m_deviceVolume))
+ notifyDeviceVolumeChanged(m_deviceVolume);
+ if (iOldTreble != m_caps.intGetTreble(m_treble))
+ notifyTrebleChanged(m_SoundStreamID, m_treble);
+ if (iOldBass != m_caps.intGetBass(m_bass))
+ notifyBassChanged(m_SoundStreamID, m_bass);
+ if (iOldBalance != m_caps.intGetBalance(m_balance))
+ notifyBalanceChanged(m_SoundStreamID, m_balance);
+
+ m_blockReadAudio = oldBlock;
+
+ return isPowerOn();
+}
+
+
+
+
+void V4LRadio::poll()
+{
+ readTunerInfo();
+ readAudioInfo();
+}
+
+
+bool V4LRadio::setPlaybackVolume(SoundStreamID id, float volume)
+{
+ if (isPowerOff() && id == m_SoundStreamID) {
+ m_defaultPlaybackVolume = min(max(volume, 0.0), 1.0);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool V4LRadio::getPlaybackVolume(SoundStreamID id, float &volume) const
+{
+ if (isPowerOff() && id == m_SoundStreamID) {
+ volume = m_defaultPlaybackVolume;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+
+bool V4LRadio::getSoundStreamDescription(SoundStreamID id, QString &descr) const
+{
+ if (id == m_SoundStreamID) {
+ descr = name() + " - " + m_currentStation.name();
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+bool V4LRadio::getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const
+{
+ if (id == m_SoundStreamID) {
+ rs = &m_currentStation;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+bool V4LRadio::enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const
+{
+ if (m_SoundStreamID.isValid()) {
+ QString tmp = QString::null;
+ getSoundStreamDescription(m_SoundStreamID, tmp);
+ list[tmp] = m_SoundStreamID;
+ return true;
+ }
+ return false;
+}
+
+
+// bool V4LRadio::stopCapture(SoundStreamID id)
+// {
+// if (id.isValid() && id == m_SoundStreamID && m_ActivePlayback) {
+// sendStopPlayback(id);
+// return true;
+// }
+// return false;
+// }
+
+#include "v4lradio.moc"
diff --git a/kradio3/plugins/v4lradio/v4lradio.h b/kradio3/plugins/v4lradio/v4lradio.h
new file mode 100644
index 0000000..4b86cb5
--- /dev/null
+++ b/kradio3/plugins/v4lradio/v4lradio.h
@@ -0,0 +1,265 @@
+/***************************************************************************
+ v4lradio.h - description
+ -------------------
+ begin : Jan 2002
+ copyright : (C) 2002-2005 Ernst Martin Witte, Klas Kalass
+ email : witte@kawo1.rwth-aachen.de, klas@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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_V4LRADIO_H
+#define KRADIO_V4LRADIO_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qtimer.h>
+
+#include "../../src/include/radiodevice_interfaces.h"
+#include "../../src/include/plugins.h"
+#include "../../src/include/frequencyradiostation.h"
+#include "../../src/include/frequencyseekhelper.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+#include "v4lcfg_interfaces.h"
+
+
+struct video_tuner;
+struct video_audio;
+#ifdef HAVE_V4L2
+struct v4l2_tuner;
+#endif
+
+class V4LRadio : public QObject,
+ public PluginBase,
+ public IRadioDevice,
+// public IRadioSound,
+ public ISeekRadio,
+ public IFrequencyRadio,
+ public ISoundStreamClient,
+ public IV4LCfg
+{
+Q_OBJECT
+public:
+ V4LRadio (const QString &name);
+ virtual ~V4LRadio ();
+
+ virtual bool connectI (Interface *);
+ virtual bool disconnectI (Interface *);
+
+ virtual QString pluginClassName() const { return "V4LRadio"; }
+
+ virtual const QString &name() const { return PluginBase::name(); }
+ virtual QString &name() { return PluginBase::name(); }
+
+ // PluginBase
+
+public:
+ virtual void saveState (KConfig *) const;
+ virtual void restoreState (KConfig *);
+ virtual void startPlugin();
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // IRadioDevice methods
+
+RECEIVERS:
+ virtual bool setPower(bool p);
+ virtual bool powerOn();
+ virtual bool powerOff();
+ virtual bool activateStation(const RadioStation &rs);
+
+ANSWERS:
+ virtual bool isPowerOn() const;
+ virtual bool isPowerOff() const;
+ virtual SoundStreamID getSoundStreamID() const;
+ virtual const RadioStation & getCurrentStation() const;
+ virtual const QString & getDescription() const;
+ virtual SoundStreamID getCurrentSoundStreamID() const;
+
+
+ // ISeekRadio
+
+RECEIVERS:
+ virtual bool toBeginning();
+ virtual bool toEnd();
+ virtual bool startSeek (bool up);
+ virtual bool startSeekUp();
+ virtual bool startSeekDown();
+ virtual bool stopSeek();
+
+ANSWERS:
+ virtual bool isSeekRunning() const;
+ virtual bool isSeekUpRunning() const;
+ virtual bool isSeekDownRunning() const;
+ virtual float getProgress () const;
+
+
+ // IFrequencyRadio
+
+RECEIVERS:
+ virtual bool setFrequency(float f);
+ virtual bool setMinFrequency(float mf);
+ virtual bool setMaxFrequency(float mf);
+ virtual bool setScanStep(float s);
+
+ANSWERS:
+ virtual float getFrequency() const;
+ virtual float getMinFrequency() const;
+ virtual float getMinDeviceFrequency() const;
+ virtual float getMaxFrequency() const;
+ virtual float getMaxDeviceFrequency() const;
+ virtual float getScanStep() const;
+
+
+ // ISoundStreamClient: mixer functions
+
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+ void noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid);
+
+ bool setTreble (SoundStreamID, float v);
+ bool setBass (SoundStreamID, float v);
+ bool setBalance (SoundStreamID, float v);
+ bool mute (SoundStreamID, bool mute = true);
+ bool unmute (SoundStreamID, bool unmute = true);
+ bool setSignalMinQuality(SoundStreamID, float q);
+ bool setStereo(SoundStreamID, bool s);
+
+ bool getTreble(SoundStreamID, float &v) const;
+ bool getBass (SoundStreamID, float &v) const;
+ bool getBalance (SoundStreamID, float &b) const;
+ bool getSignalQuality(SoundStreamID, float &q) const;
+ bool getSignalMinQuality(SoundStreamID, float &q) const;
+ bool hasGoodQuality(SoundStreamID, bool &) const;
+ bool isStereo(SoundStreamID, bool &s) const;
+ bool isMuted(SoundStreamID, bool &m) const;
+
+ // ISoundStreamClient: generic stream handling (broadcasts)
+
+RECEIVERS:
+
+ bool getSoundStreamDescription(SoundStreamID id, QString &descr) const;
+ bool getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const;
+ bool enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const;
+
+// bool stopCapture(SoundStreamID id); // if active playback also call stopPlayback
+
+
+ // IV4LCfg
+RECEIVERS:
+ bool setRadioDevice (const QString &s);
+ bool setPlaybackMixer(const QString &soundStreamClientID, const QString &ch);
+ bool setCaptureMixer (const QString &soundStreamClientID, const QString &ch);
+ bool setDeviceVolume (float v);
+ bool setActivePlayback(bool a);
+ bool setMuteOnPowerOff(bool a);
+ bool setVolumeZeroOnPowerOff(bool a);
+
+ // if the radio is powered off, we will handle the volume by changing m_defaultPlaybackVolume
+ bool setPlaybackVolume(SoundStreamID id, float volume);
+ bool getPlaybackVolume(SoundStreamID id, float &volume) const;
+
+ANSWERS:
+ const QString &getRadioDevice () const { return m_radioDev; }
+ const QString &getPlaybackMixerID () const { return m_PlaybackMixerID; }
+ const QString &getCaptureMixerID () const { return m_CaptureMixerID; }
+ const QString &getPlaybackMixerChannel() const { return m_PlaybackMixerChannel; }
+ const QString &getCaptureMixerChannel () const { return m_CaptureMixerChannel; }
+ float getDeviceVolume () const;
+ V4LCaps getCapabilities(QString dev = QString::null) const;
+
+ bool getActivePlayback() const { return m_ActivePlayback; }
+ bool getMuteOnPowerOff() const { return m_MuteOnPowerOff; }
+ bool getVolumeZeroOnPowerOff() const { return m_VolumeZeroOnPowerOff; }
+
+ // anything else
+
+protected slots:
+ void poll();
+
+protected:
+ V4LCaps readV4LCaps(const QString &device) const;
+ void radio_init();
+ void radio_done();
+
+ bool readTunerInfo() const;
+ bool updateAudioInfo(bool write) const;
+ bool readAudioInfo() const { return updateAudioInfo(false); }
+ bool writeAudioInfo() const { return updateAudioInfo(true); }
+
+ void searchMixers(ISoundStreamClient **playback_mixer, ISoundStreamClient **capture_mixer);
+
+protected:
+
+ FrequencyRadioStation m_currentStation;
+ mutable float m_treble;
+ mutable float m_bass;
+ mutable float m_balance;
+ mutable float m_deviceVolume;
+ mutable bool m_muted;
+ mutable float m_signalQuality;
+ mutable bool m_stereo;
+
+ float m_minQuality;
+ float m_minFrequency;
+ float m_maxFrequency;
+ mutable float m_lastMinDevFrequency;
+ mutable float m_lastMaxDevFrequency;
+
+ float m_defaultPlaybackVolume;
+
+ FrequencySeekHelper *m_seekHelper;
+ float m_scanStep;
+
+ V4LCaps m_caps;
+ QString m_radioDev;
+ int m_radio_fd;
+
+ mutable bool m_useOldV4L2Calls;
+
+
+ mutable struct video_audio *m_audio;
+ mutable struct video_tuner *m_tuner;
+#ifdef HAVE_V4L2
+ mutable struct v4l2_tuner *m_tuner2;
+#endif
+
+ QTimer m_pollTimer;
+
+ struct TunerCache {
+ bool valid;
+ float deltaF;
+ float minF, maxF;
+ TunerCache() { valid = false; deltaF = minF = maxF = 0; }
+ };
+ mutable struct TunerCache m_tunercache;
+
+
+ mutable bool m_blockReadTuner,
+ m_blockReadAudio;
+
+ SoundStreamID m_SoundStreamID;
+ QString m_PlaybackMixerID;
+ QString m_CaptureMixerID;
+ QString m_PlaybackMixerChannel;
+ QString m_CaptureMixerChannel;
+
+ bool m_ActivePlayback;
+ bool m_MuteOnPowerOff;
+ bool m_VolumeZeroOnPowerOff;
+
+ bool m_restorePowerOn;
+};
+
+#endif